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

Compare commits

..

5 Commits

Author SHA1 Message Date
Gerard Mista 59a8490540 Artifact should have same version as release. (#974) 2022-07-01 14:21:42 -07:00
Yury Semikhatsky a127bfefb3 cherry-pick(#978,#984): recent test fixes (#985) 2022-06-30 14:47:57 -07:00
Yury Semikhatsky 06082438fe cherry-pick(#982): feat: roll driver to 1.23.1-beta, implement routeFromHar.update (#983) 2022-06-30 13:17:18 -07:00
Yury Semikhatsky b8bd59a55c chore: mark 1.23.0 (#971) 2022-06-28 09:14:00 -07:00
Yury Semikhatsky e42d7bdc9a cherry-pick(#969): feat: support ignoreCase option (#970) 2022-06-28 08:50:34 -07:00
137 changed files with 1902 additions and 2454 deletions
+2 -4
View File
@@ -1,5 +1,3 @@
# text files must be lf for golden file tests to work
* text=auto eol=lf
# make project show as TS on GitHub
*.js linguist-detectable=false
*.txt eol=lf
*.json eol=lf
+4 -12
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 -->106.0.5249.30<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| WebKit <!-- GEN:webkit-version -->16.0<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Firefox <!-- GEN:firefox-version -->104.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Chromium <!-- GEN:chromium-version -->104.0.5112.20<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| WebKit <!-- GEN:webkit-version -->15.4<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Firefox <!-- GEN:firefox-version -->100.0.2<!-- 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.
@@ -43,18 +43,10 @@ To run Playwright simply add following dependency to your Maven project:
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<version>1.17.0</version>
<version>1.23.0</version>
</dependency>
```
To run Playwright using Gradle add following dependency to your build.gradle file:
```json lines
dependencies {
implementation group: 'com.microsoft.playwright', name: 'playwright', version: '1.25.0'
}
```
#### Is Playwright thread-safe?
No, Playwright is not thread safe, i.e. all its methods as well as methods on all objects created by it (such as BrowserContext, Browser, Page etc.) are expected to be called on the same thread where Playwright object was created or proper synchronization should be implemented to ensure only one thread calls Playwright methods at any given time. Having said that it's okay to create multiple Playwright instances each on its own thread.
+1 -1
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>com.microsoft.playwright</groupId>
<artifactId>parent-pom</artifactId>
<version>1.26.1</version>
<version>1.23.0</version>
</parent>
<artifactId>driver-bundle</artifactId>
@@ -14,9 +14,7 @@
* limitations under the License.
*/
package com.microsoft.playwright.impl.driver.jar;
import com.microsoft.playwright.impl.driver.Driver;
package com.microsoft.playwright.impl;
import java.io.IOException;
import java.net.URI;
@@ -28,10 +26,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";
static final String PLAYWRIGHT_NODEJS_PATH = "PLAYWRIGHT_NODEJS_PATH";
private final Path driverTempDir;
private Path preinstalledNodePath;
public DriverJar() throws IOException {
// Allow specifying custom path for the driver installation
@@ -42,27 +37,11 @@ public class DriverJar extends Driver {
? Files.createTempDirectory(prefix)
: Files.createTempDirectory(Paths.get(alternativeTmpdir), prefix);
driverTempDir.toFile().deleteOnExit();
String nodePath = System.getProperty("playwright.nodejs.path");
if (nodePath != null) {
preinstalledNodePath = Paths.get(nodePath);
if (!Files.exists(preinstalledNodePath)) {
throw new RuntimeException("Invalid Node.js path specified: " + nodePath);
}
}
logMessage("created DriverJar: " + driverTempDir);
}
@Override
protected void initialize(Boolean installBrowsers) throws Exception {
if (preinstalledNodePath == null && env.containsKey(PLAYWRIGHT_NODEJS_PATH)) {
preinstalledNodePath = Paths.get(env.get(PLAYWRIGHT_NODEJS_PATH));
if (!Files.exists(preinstalledNodePath)) {
throw new RuntimeException("Invalid Node.js path specified: " + preinstalledNodePath);
}
} else if (preinstalledNodePath != null) {
// Pass the env variable to the driver process.
env.put(PLAYWRIGHT_NODEJS_PATH, preinstalledNodePath.toString());
}
protected void initialize(Map<String, String> env, Boolean installBrowsers) throws Exception {
extractDriverToTempDir();
logMessage("extracted driver from jar to " + driverPath());
if (installBrowsers)
@@ -78,16 +57,13 @@ 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);
}
ProcessBuilder pb = createProcessBuilder();
pb.command().add("install");
ProcessBuilder pb = new ProcessBuilder(driver.toString(), "install");
pb.environment().putAll(env);
setRequiredEnvironmentVariables(pb);
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
Process p = pb.start();
@@ -106,10 +82,9 @@ public class DriverJar extends Driver {
return name.endsWith(".sh") || name.endsWith(".exe") || !name.contains(".");
}
void extractDriverToTempDir() throws URISyntaxException, IOException {
private void extractDriverToTempDir() throws URISyntaxException, IOException {
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
URI originalUri = classloader.getResource(
"driver/" + platformDir()).toURI();
URI originalUri = classloader.getResource("driver/" + platformDir()).toURI();
URI uri = maybeExtractNestedJar(originalUri);
// Create zip filesystem if loading from jar.
@@ -121,12 +96,6 @@ public class DriverJar extends Driver {
// See https://github.com/microsoft/playwright-java/issues/306
Path srcRootDefaultFs = Paths.get(srcRoot.toString());
Files.walk(srcRoot).forEach(fromPath -> {
if (preinstalledNodePath != null) {
String fileName = fromPath.getFileName().toString();
if ("node.exe".equals(fileName) || "node".equals(fileName)) {
return;
}
}
Path relative = srcRootDefaultFs.relativize(Paths.get(fromPath.toString()));
Path toPath = driverTempDir.resolve(relative.toString());
try {
@@ -189,7 +158,7 @@ public class DriverJar extends Driver {
}
@Override
protected Path driverDir() {
Path driverDir() {
return driverTempDir;
}
}
@@ -14,19 +14,18 @@
* limitations under the License.
*/
package com.microsoft.playwright.impl.driver.jar;
package com.microsoft.playwright;
import com.microsoft.playwright.impl.driver.Driver;
import org.junit.jupiter.api.AfterEach;
import com.microsoft.playwright.impl.Driver;
import com.microsoft.playwright.impl.DriverJar;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
@@ -34,8 +33,6 @@ import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static com.microsoft.playwright.impl.driver.jar.DriverJar.PLAYWRIGHT_NODEJS_PATH;
import static java.util.Collections.singletonMap;
import static org.junit.jupiter.api.Assertions.*;
public class TestInstall {
@@ -61,13 +58,12 @@ public class TestInstall {
// Clear system property to ensure that the driver is loaded from jar.
System.clearProperty("playwright.cli.dir");
System.clearProperty("playwright.driver.tmpdir");
System.clearProperty("playwright.nodejs.path");
// Clear system property to ensure that the default driver is loaded.
System.clearProperty("playwright.driver.impl");
}
@Test
void shouldThrowWhenBrowserPathIsInvalid(@TempDir Path tmpDir) throws NoSuchFieldException, IllegalAccessException {
void shouldThrowWhenBrowserPathIsInvalid(@TempDir Path tmpDir) throws MalformedURLException, ClassNotFoundException, NoSuchMethodException, NoSuchFieldException, IllegalAccessException {
Map<String,String> env = new HashMap<>();
// On macOS we can only use 127.0.0.1, so pick unused port instead.
@@ -77,18 +73,27 @@ public class TestInstall {
env.put("PLAYWRIGHT_BROWSERS_PATH", tmpDir.toString());
env.put("PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD", "false");
RuntimeException exception = assertThrows(RuntimeException.class, () -> Driver.createAndInstall(env, true));
String message = exception.getMessage();
assertTrue(message.contains("Failed to create driver"), message);
// Reset instance field value to null for the test.
Field field = Driver.class.getDeclaredField("instance");
field.setAccessible(true);
Object value = field.get(Driver.class);
field.set(Driver.class, null);
for (int i = 0; i < 2; i++){
RuntimeException exception = assertThrows(RuntimeException.class, () -> Driver.ensureDriverInstalled(env, true));
String message = exception.getMessage();
assertTrue(message.contains("Failed to create driver"), message);
}
field.set(Driver.class, value);
}
@Test
void playwrightCliInstalled() throws Exception {
Driver driver = Driver.createAndInstall(Collections.emptyMap(), false);
assertTrue(Files.exists(driver.driverPath()));
Path cli = Driver.ensureDriverInstalled(Collections.emptyMap(), false);
assertTrue(Files.exists(cli));
ProcessBuilder pb = driver.createProcessBuilder();
pb.command().add("install");
ProcessBuilder pb = new ProcessBuilder(cli.toString(), "install");
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
Process p = pb.start();
@@ -105,62 +110,16 @@ public class TestInstall {
@Test
void playwrightDriverDefaultImpl() {
assertDoesNotThrow(() -> Driver.createAndInstall(Collections.emptyMap(), false));
assertDoesNotThrow(() -> Driver.ensureDriverInstalled(Collections.emptyMap(), false));
}
@Test
void playwrightDriverAlternativeImpl() throws NoSuchFieldException, IllegalAccessException {
void playwrightDriverAlternativeImpl() {
System.setProperty("playwright.driver.impl", "com.microsoft.playwright.impl.AlternativeDriver");
RuntimeException thrown =
assertThrows(
RuntimeException.class,
() -> Driver.createAndInstall(Collections.emptyMap(), false));
() -> Driver.ensureDriverInstalled(Collections.emptyMap(), false));
assertEquals("Failed to create driver", thrown.getMessage());
}
@Test
void canPassPreinstalledNodeJsAsSystemProperty(@TempDir Path tmpDir) throws IOException, URISyntaxException, InterruptedException {
String nodePath = extractNodeJsToTemp();
System.setProperty("playwright.nodejs.path", nodePath);
Driver driver = Driver.createAndInstall(Collections.emptyMap(), false);
canSpecifyPreinstalledNodeJsShared(driver, tmpDir);
}
@Test
void canSpecifyPreinstalledNodeJsAsEnv(@TempDir Path tmpDir) throws IOException, URISyntaxException, InterruptedException {
String nodePath = extractNodeJsToTemp();
Driver driver = Driver.createAndInstall(singletonMap(PLAYWRIGHT_NODEJS_PATH, nodePath), false);
canSpecifyPreinstalledNodeJsShared(driver, tmpDir);
}
private static String extractNodeJsToTemp() throws URISyntaxException, IOException {
DriverJar auxDriver = new DriverJar();
auxDriver.extractDriverToTempDir();
String nodePath = auxDriver.driverPath().getParent().resolve(isWindows() ? "node.exe" : "node").toString();
return nodePath;
}
private static boolean isWindows() {
String name = System.getProperty("os.name").toLowerCase();
return name.contains("win");
}
private static void canSpecifyPreinstalledNodeJsShared(Driver driver, Path tmpDir) throws IOException, URISyntaxException, InterruptedException {
Path builtinNode = driver.driverPath().getParent().resolve("node");
assertFalse(Files.exists(builtinNode), builtinNode.toString());
Path builtinNodeExe = driver.driverPath().getParent().resolve("node.exe");
assertFalse(Files.exists(builtinNodeExe), builtinNodeExe.toString());
ProcessBuilder pb = driver.createProcessBuilder();
pb.command().add("--version");
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
Path out = tmpDir.resolve("out.txt");
pb.redirectOutput(out.toFile());
Process p = pb.start();
boolean result = p.waitFor(1, TimeUnit.MINUTES);
assertTrue(result, "Timed out waiting for version to be printed");
String stdout = new String(Files.readAllBytes(out), StandardCharsets.UTF_8);
assertTrue(stdout.contains("Version "), stdout);
}
}
+1 -1
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>com.microsoft.playwright</groupId>
<artifactId>parent-pom</artifactId>
<version>1.26.1</version>
<version>1.23.0</version>
</parent>
<artifactId>driver</artifactId>
@@ -14,15 +14,14 @@
* limitations under the License.
*/
package com.microsoft.playwright.impl.driver;
package com.microsoft.playwright.impl;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.time.ZonedDateTime;
import java.util.Map;
import static com.microsoft.playwright.impl.driver.DriverLogging.logWithTimestamp;
import static com.microsoft.playwright.impl.DriverLogging.logWithTimestamp;
/**
* This class provides access to playwright-cli. It can be either preinstalled
@@ -30,8 +29,6 @@ import static com.microsoft.playwright.impl.driver.DriverLogging.logWithTimestam
* loaded from the driver-bundle module if that module is in the classpath.
*/
public abstract class Driver {
protected final Map<String, String> env = new LinkedHashMap<>();
private static Driver instance;
private static class PreinstalledDriver extends Driver {
@@ -42,28 +39,32 @@ public abstract class Driver {
}
@Override
protected void initialize(Boolean installBrowsers) {
protected void initialize(Map<String, String> env, Boolean installBrowsers) {
// no-op
}
@Override
protected Path driverDir() {
Path driverDir() {
return driverDir;
}
}
public static synchronized Driver ensureDriverInstalled(Map<String, String> env, Boolean installBrowsers) {
public static synchronized Path ensureDriverInstalled(Map<String, String> env, Boolean installBrowsers) {
if (instance == null) {
instance = createAndInstall(env, installBrowsers);
try {
instance = createDriver();
logMessage("initializing driver");
instance.initialize(env, installBrowsers);
logMessage("driver initialized.");
} catch (Exception exception) {
instance = null;
throw new RuntimeException("Failed to create driver", exception);
}
}
return instance;
return instance.driverPath();
}
private void initialize(Map<String, String> env, Boolean installBrowsers) throws Exception {
this.env.putAll(env);
initialize(installBrowsers);
}
protected abstract void initialize(Boolean installBrowsers) throws Exception;
protected abstract void initialize(Map<String, String> env, Boolean installBrowsers) throws Exception;
public Path driverPath() {
String cliFileName = System.getProperty("os.name").toLowerCase().contains("windows") ?
@@ -71,16 +72,13 @@ public abstract class Driver {
return driverDir().resolve(cliFileName);
}
public ProcessBuilder createProcessBuilder() {
ProcessBuilder pb = new ProcessBuilder(driverPath().toString());
pb.environment().putAll(env);
public static void setRequiredEnvironmentVariables(ProcessBuilder pb) {
pb.environment().put("PW_LANG_NAME", "java");
pb.environment().put("PW_LANG_NAME_VERSION", getMajorJavaVersion());
String version = Driver.class.getPackage().getImplementationVersion();
if (version != null) {
pb.environment().put("PW_CLI_DISPLAY_VERSION", version);
}
return pb;
}
private static String getMajorJavaVersion() {
@@ -94,31 +92,20 @@ public abstract class Driver {
}
return version;
}
public static Driver createAndInstall(Map<String, String> env, Boolean installBrowsers) {
try {
Driver instance = newInstance();
logMessage("initializing driver");
instance.initialize(env, installBrowsers);
logMessage("driver initialized.");
return instance;
} catch (Exception exception) {
throw new RuntimeException("Failed to create driver", exception);
}
}
private static Driver newInstance() throws Exception {
private static Driver createDriver() throws Exception {
String pathFromProperty = System.getProperty("playwright.cli.dir");
if (pathFromProperty != null) {
return new PreinstalledDriver(Paths.get(pathFromProperty));
}
String driverImpl =
System.getProperty("playwright.driver.impl", "com.microsoft.playwright.impl.driver.jar.DriverJar");
System.getProperty("playwright.driver.impl", "com.microsoft.playwright.impl.DriverJar");
Class<?> jarDriver = Class.forName(driverImpl);
return (Driver) jarDriver.getDeclaredConstructor().newInstance();
}
protected abstract Path driverDir();
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.driver;
package com.microsoft.playwright.impl;
import java.time.ZoneId;
import java.time.ZonedDateTime;
+2 -2
View File
@@ -6,7 +6,7 @@
<groupId>org.example</groupId>
<artifactId>examples</artifactId>
<version>1.26.1</version>
<version>1.23.0</version>
<name>Playwright Client Examples</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -15,7 +15,7 @@
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<version>1.22.0</version>
<version>1.23.0</version>
</dependency>
</dependencies>
<build>
+1 -1
View File
@@ -7,7 +7,7 @@
<parent>
<groupId>com.microsoft.playwright</groupId>
<artifactId>parent-pom</artifactId>
<version>1.26.1</version>
<version>1.23.0</version>
</parent>
<artifactId>playwright</artifactId>
@@ -30,15 +30,15 @@ import java.nio.file.Path;
*
* <p> **Cookie management**
*
* <p> {@code APIRequestContext} returned by {@link BrowserContext#request BrowserContext.request()} and {@link Page#request
* <p> {@code APIRequestContext} retuned 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 should 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 shoud 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 {
@@ -95,6 +95,9 @@ public interface Browser extends AutoCloseable {
/**
* Emulates {@code "forced-colors"} media feature, supported values are {@code "active"}, {@code "none"}. See {@link Page#emulateMedia
* Page.emulateMedia()} for more details. Defaults to {@code "none"}.
*
* <p> <strong>NOTE:</strong> It's not supported in WebKit, see <a href="https://bugs.webkit.org/show_bug.cgi?id=225281">here</a> in their issue
* tracker.
*/
public ForcedColors forcedColors;
public Geolocation geolocation;
@@ -281,6 +284,9 @@ public interface Browser extends AutoCloseable {
/**
* Emulates {@code "forced-colors"} media feature, supported values are {@code "active"}, {@code "none"}. See {@link Page#emulateMedia
* Page.emulateMedia()} for more details. Defaults to {@code "none"}.
*
* <p> <strong>NOTE:</strong> It's not supported in WebKit, see <a href="https://bugs.webkit.org/show_bug.cgi?id=225281">here</a> in their issue
* tracker.
*/
public NewContextOptions setForcedColors(ForcedColors forcedColors) {
this.forcedColors = forcedColors;
@@ -575,6 +581,9 @@ public interface Browser extends AutoCloseable {
/**
* Emulates {@code "forced-colors"} media feature, supported values are {@code "active"}, {@code "none"}. See {@link Page#emulateMedia
* Page.emulateMedia()} for more details. Defaults to {@code "none"}.
*
* <p> <strong>NOTE:</strong> It's not supported in WebKit, see <a href="https://bugs.webkit.org/show_bug.cgi?id=225281">here</a> in their issue
* tracker.
*/
public ForcedColors forcedColors;
public Geolocation geolocation;
@@ -761,6 +770,9 @@ public interface Browser extends AutoCloseable {
/**
* Emulates {@code "forced-colors"} media feature, supported values are {@code "active"}, {@code "none"}. See {@link Page#emulateMedia
* Page.emulateMedia()} for more details. Defaults to {@code "none"}.
*
* <p> <strong>NOTE:</strong> It's not supported in WebKit, see <a href="https://bugs.webkit.org/show_bug.cgi?id=225281">here</a> in their issue
* tracker.
*/
public NewPageOptions setForcedColors(ForcedColors forcedColors) {
this.forcedColors = forcedColors;
@@ -1063,10 +1075,6 @@ public interface Browser extends AutoCloseable {
* <p> In case this browser is connected to, clears all created contexts belonging to this browser and disconnects from the
* browser server.
*
* <p> <strong>NOTE:</strong> This is similar to force quitting the browser. Therefore, you should call {@link BrowserContext#close
* BrowserContext.close()} on any {@code BrowserContext}'s you explicitly created earlier with {@link Browser#newContext
* Browser.newContext()} **before** calling {@link Browser#close Browser.close()}.
*
* <p> The {@code Browser} object itself is considered to be disposed and cannot be used anymore.
*/
void close();
@@ -1086,11 +1094,6 @@ public interface Browser extends AutoCloseable {
boolean isConnected();
/**
* 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 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.
* <pre>{@code
* Browser browser = playwright.firefox().launch(); // Or 'chromium' or 'webkit'.
* // Create a new incognito browser context.
@@ -1098,10 +1101,6 @@ public interface Browser extends AutoCloseable {
* // Create a new page in a pristine context.
* Page page = context.newPage();
* page.navigate('https://example.com');
*
* // Graceful close up everything
* context.close();
* browser.close();
* }</pre>
*/
default BrowserContext newContext() {
@@ -1109,11 +1108,6 @@ 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 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.
* <pre>{@code
* Browser browser = playwright.firefox().launch(); // Or 'chromium' or 'webkit'.
* // Create a new incognito browser context.
@@ -1121,10 +1115,6 @@ public interface Browser extends AutoCloseable {
* // Create a new page in a pristine context.
* Page page = context.newPage();
* page.navigate('https://example.com');
*
* // Graceful close up everything
* context.close();
* browser.close();
* }</pre>
*/
BrowserContext newContext(NewContextOptions options);
@@ -67,7 +67,7 @@ public interface BrowserContext extends AutoCloseable {
* done and its response has started loading in the popup.
* <pre>{@code
* Page newPage = context.waitForPage(() -> {
* page.locator("a[target=_blank]").click();
* page.click("a[target=_blank]");
* });
* System.out.println(newPage.evaluate("location.href"));
* }</pre>
@@ -190,7 +190,7 @@ public interface BrowserContext extends AutoCloseable {
public Boolean update;
/**
* A glob pattern, regular expression or predicate to match the request URL. Only requests with URL matching the pattern
* will be served from the HAR file. If not specified, all requests are served from the HAR file.
* will be surved from the HAR file. If not specified, all requests are served from the HAR file.
*/
public Object url;
@@ -215,7 +215,7 @@ public interface BrowserContext extends AutoCloseable {
}
/**
* A glob pattern, regular expression or predicate to match the request URL. Only requests with URL matching the pattern
* will be served from the HAR file. If not specified, all requests are served from the HAR file.
* will be surved from the HAR file. If not specified, all requests are served from the HAR file.
*/
public RouteFromHAROptions setUrl(String url) {
this.url = url;
@@ -223,7 +223,7 @@ public interface BrowserContext extends AutoCloseable {
}
/**
* A glob pattern, regular expression or predicate to match the request URL. Only requests with URL matching the pattern
* will be served from the HAR file. If not specified, all requests are served from the HAR file.
* will be surved from the HAR file. If not specified, all requests are served from the HAR file.
*/
public RouteFromHAROptions setUrl(Pattern url) {
this.url = url;
@@ -404,7 +404,7 @@ public interface BrowserContext extends AutoCloseable {
* "</script>\n" +
* "<button onclick=\"onClick()\">Click me</button>\n" +
* "<div></div>");
* page.locator("button").click();
* page.click("button");
* }
* }
* }
@@ -463,7 +463,7 @@ public interface BrowserContext extends AutoCloseable {
* "</script>\n" +
* "<button onclick=\"onClick()\">Click me</button>\n" +
* "<div></div>");
* page.locator("button").click();
* page.click("button");
* }
* }
* }
@@ -533,7 +533,7 @@ public interface BrowserContext extends AutoCloseable {
* "</script>\n" +
* "<button onclick=\"onClick()\">Click me</button>\n" +
* "<div></div>\n");
* page.locator("button").click();
* page.click("button");
* }
* }
* }
@@ -442,6 +442,9 @@ public interface BrowserType {
/**
* Emulates {@code "forced-colors"} media feature, supported values are {@code "active"}, {@code "none"}. See {@link Page#emulateMedia
* Page.emulateMedia()} for more details. Defaults to {@code "none"}.
*
* <p> <strong>NOTE:</strong> It's not supported in WebKit, see <a href="https://bugs.webkit.org/show_bug.cgi?id=225281">here</a> in their issue
* tracker.
*/
public ForcedColors forcedColors;
public Geolocation geolocation;
@@ -722,6 +725,9 @@ public interface BrowserType {
/**
* Emulates {@code "forced-colors"} media feature, supported values are {@code "active"}, {@code "none"}. See {@link Page#emulateMedia
* Page.emulateMedia()} for more details. Defaults to {@code "none"}.
*
* <p> <strong>NOTE:</strong> It's not supported in WebKit, see <a href="https://bugs.webkit.org/show_bug.cgi?id=225281">here</a> in their issue
* tracker.
*/
public LaunchPersistentContextOptions setForcedColors(ForcedColors forcedColors) {
this.forcedColors = forcedColors;
@@ -1022,9 +1028,7 @@ public interface BrowserType {
}
}
/**
* 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).
* This method attaches Playwright to an existing browser instance.
*
* @param wsEndpoint A browser websocket endpoint to connect to.
*/
@@ -1032,9 +1036,7 @@ public interface BrowserType {
return connect(wsEndpoint, null);
}
/**
* 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).
* This method attaches Playwright to an existing browser instance.
*
* @param wsEndpoint A browser websocket endpoint to connect to.
*/
@@ -1045,11 +1047,6 @@ public interface BrowserType {
* <p> The default browser context is accessible via {@link Browser#contexts Browser.contexts()}.
*
* <p> <strong>NOTE:</strong> Connecting over the Chrome DevTools Protocol is only supported for Chromium-based browsers.
* <pre>{@code
* Browser browser = playwright.chromium().connectOverCDP("http://localhost:9222");
* BrowserContext defaultContext = browser.contexts().get(0);
* Page page = defaultContext.pages().get(0);
* }</pre>
*
* @param endpointURL A CDP websocket endpoint or http url to connect to. For example {@code http://localhost:9222/} or
* {@code ws://127.0.0.1:9222/devtools/browser/387adf4c-243f-4051-a181-46798f4a46f4}.
@@ -1063,11 +1060,6 @@ public interface BrowserType {
* <p> The default browser context is accessible via {@link Browser#contexts Browser.contexts()}.
*
* <p> <strong>NOTE:</strong> Connecting over the Chrome DevTools Protocol is only supported for Chromium-based browsers.
* <pre>{@code
* Browser browser = playwright.chromium().connectOverCDP("http://localhost:9222");
* BrowserContext defaultContext = browser.contexts().get(0);
* Page page = defaultContext.pages().get(0);
* }</pre>
*
* @param endpointURL A CDP websocket endpoint or http url to connect to. For example {@code http://localhost:9222/} or
* {@code ws://127.0.0.1:9222/devtools/browser/387adf4c-243f-4051-a181-46798f4a46f4}.
@@ -16,7 +16,7 @@
package com.microsoft.playwright;
import com.microsoft.playwright.impl.driver.Driver;
import com.microsoft.playwright.impl.Driver;
import java.io.IOException;
import java.nio.file.Path;
@@ -29,9 +29,10 @@ import static java.util.Arrays.asList;
*/
public class CLI {
public static void main(String[] args) throws IOException, InterruptedException {
Driver driver = Driver.ensureDriverInstalled(Collections.emptyMap(), false);
ProcessBuilder pb = driver.createProcessBuilder();
Path driver = Driver.ensureDriverInstalled(Collections.emptyMap(), false);
ProcessBuilder pb = new ProcessBuilder(driver.toString());
pb.command().addAll(asList(args));
Driver.setRequiredEnvironmentVariables(pb);
String version = Playwright.class.getPackage().getImplementationVersion();
if (version != null) {
pb.environment().put("PW_CLI_DISPLAY_VERSION", version);
@@ -27,14 +27,14 @@ import java.nio.file.Path;
* <p> Download event is emitted once the download starts. Download path becomes available once download completes:
* <pre>{@code
* // wait for download to start
* Download download = page.waitForDownload(() -> page.locator("a").click());
* Download download = page.waitForDownload(() -> page.click("a"));
* // wait for download to complete
* Path path = download.path();
* }</pre>
* <pre>{@code
* // wait for download to start
* Download download = page.waitForDownload(() -> {
* page.locator("a").click();
* page.click("a");
* });
* // wait for download to complete
* Path path = download.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 overlaid with a pink box
* Specify locators that should be masked when the screenshot is taken. Masked elements will be overlayed 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 overlaid with a pink box
* Specify locators that should be masked when the screenshot is taken. Masked elements will be overlayed with a pink box
* {@code #FF00FF} that completely covers its bounding box.
*/
public ScreenshotOptions setMask(List<Locator> mask) {
@@ -1166,7 +1166,7 @@ public interface ElementHandle extends JSHandle {
*/
public WaitForSelectorState state;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1193,7 +1193,7 @@ public interface ElementHandle extends JSHandle {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public WaitForSelectorOptions setStrict(boolean strict) {
@@ -1214,7 +1214,7 @@ public interface ElementHandle extends JSHandle {
* This method returns the bounding box of the element, or {@code null} if the element is not visible. The bounding box is
* calculated relative to the main frame viewport - which is usually the same as the browser window.
*
* <p> Scrolling affects the returned bounding box, similarly to <a
* <p> Scrolling affects the returned bonding box, similarly to <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect">Element.getBoundingClientRect</a>.
* That means {@code x} and/or {@code y} may be negative.
*
@@ -22,7 +22,7 @@ import java.nio.file.Path;
/**
* {@code FileChooser} objects are dispatched by the page in the {@link Page#onFileChooser Page.onFileChooser()} event.
* <pre>{@code
* FileChooser fileChooser = page.waitForFileChooser(() -> page.locator("upload").click());
* FileChooser fileChooser = page.waitForFileChooser(() -> page.click("upload"));
* fileChooser.setFiles(Paths.get("myfile.pdf"));
* }</pre>
*/
@@ -167,7 +167,7 @@ public interface Frame {
*/
public Position position;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -217,7 +217,7 @@ public interface Frame {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public CheckOptions setStrict(boolean strict) {
@@ -278,7 +278,7 @@ public interface Frame {
*/
public Position position;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -357,7 +357,7 @@ public interface Frame {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public ClickOptions setStrict(boolean strict) {
@@ -414,7 +414,7 @@ public interface Frame {
*/
public Position position;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -486,7 +486,7 @@ public interface Frame {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public DblclickOptions setStrict(boolean strict) {
@@ -514,7 +514,7 @@ public interface Frame {
}
class DispatchEventOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -526,7 +526,7 @@ public interface Frame {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public DispatchEventOptions setStrict(boolean strict) {
@@ -561,7 +561,7 @@ public interface Frame {
*/
public Position sourcePosition;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -616,7 +616,7 @@ public interface Frame {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public DragAndDropOptions setStrict(boolean strict) {
@@ -659,13 +659,13 @@ public interface Frame {
}
class EvalOnSelectorOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public EvalOnSelectorOptions setStrict(boolean strict) {
@@ -686,7 +686,7 @@ public interface Frame {
*/
public Boolean noWaitAfter;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -715,7 +715,7 @@ public interface Frame {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public FillOptions setStrict(boolean strict) {
@@ -734,7 +734,7 @@ public interface Frame {
}
class FocusOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -746,7 +746,7 @@ public interface Frame {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public FocusOptions setStrict(boolean strict) {
@@ -765,7 +765,7 @@ public interface Frame {
}
class GetAttributeOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -777,7 +777,7 @@ public interface Frame {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public GetAttributeOptions setStrict(boolean strict) {
@@ -867,7 +867,7 @@ public interface Frame {
*/
public Position position;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -916,7 +916,7 @@ public interface Frame {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public HoverOptions setStrict(boolean strict) {
@@ -944,7 +944,7 @@ public interface Frame {
}
class InnerHTMLOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -956,7 +956,7 @@ public interface Frame {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public InnerHTMLOptions setStrict(boolean strict) {
@@ -975,7 +975,7 @@ public interface Frame {
}
class InnerTextOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -987,7 +987,7 @@ public interface Frame {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public InnerTextOptions setStrict(boolean strict) {
@@ -1006,7 +1006,7 @@ public interface Frame {
}
class InputValueOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1018,7 +1018,7 @@ public interface Frame {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public InputValueOptions setStrict(boolean strict) {
@@ -1037,7 +1037,7 @@ public interface Frame {
}
class IsCheckedOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1049,7 +1049,7 @@ public interface Frame {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public IsCheckedOptions setStrict(boolean strict) {
@@ -1068,7 +1068,7 @@ public interface Frame {
}
class IsDisabledOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1080,7 +1080,7 @@ public interface Frame {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public IsDisabledOptions setStrict(boolean strict) {
@@ -1099,7 +1099,7 @@ public interface Frame {
}
class IsEditableOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1111,7 +1111,7 @@ public interface Frame {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public IsEditableOptions setStrict(boolean strict) {
@@ -1130,7 +1130,7 @@ public interface Frame {
}
class IsEnabledOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1142,7 +1142,7 @@ public interface Frame {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public IsEnabledOptions setStrict(boolean strict) {
@@ -1161,7 +1161,7 @@ public interface Frame {
}
class IsHiddenOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1172,7 +1172,7 @@ public interface Frame {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public IsHiddenOptions setStrict(boolean strict) {
@@ -1190,7 +1190,7 @@ public interface Frame {
}
class IsVisibleOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1201,7 +1201,7 @@ public interface Frame {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public IsVisibleOptions setStrict(boolean strict) {
@@ -1273,7 +1273,7 @@ public interface Frame {
*/
public Boolean noWaitAfter;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1301,7 +1301,7 @@ public interface Frame {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public PressOptions setStrict(boolean strict) {
@@ -1320,13 +1320,13 @@ public interface Frame {
}
class QuerySelectorOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public QuerySelectorOptions setStrict(boolean strict) {
@@ -1347,7 +1347,7 @@ public interface Frame {
*/
public Boolean noWaitAfter;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1376,7 +1376,7 @@ public interface Frame {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public SelectOptionOptions setStrict(boolean strict) {
@@ -1411,7 +1411,7 @@ public interface Frame {
*/
public Position position;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1461,7 +1461,7 @@ public interface Frame {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public SetCheckedOptions setStrict(boolean strict) {
@@ -1538,7 +1538,7 @@ public interface Frame {
*/
public Boolean noWaitAfter;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1559,7 +1559,7 @@ public interface Frame {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public SetInputFilesOptions setStrict(boolean strict) {
@@ -1599,7 +1599,7 @@ public interface Frame {
*/
public Position position;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1657,7 +1657,7 @@ public interface Frame {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public TapOptions setStrict(boolean strict) {
@@ -1685,7 +1685,7 @@ public interface Frame {
}
class TextContentOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1697,7 +1697,7 @@ public interface Frame {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public TextContentOptions setStrict(boolean strict) {
@@ -1726,7 +1726,7 @@ public interface Frame {
*/
public Boolean noWaitAfter;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1754,7 +1754,7 @@ public interface Frame {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public TypeOptions setStrict(boolean strict) {
@@ -1789,7 +1789,7 @@ public interface Frame {
*/
public Position position;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1839,7 +1839,7 @@ public interface Frame {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public UncheckOptions setStrict(boolean strict) {
@@ -2004,7 +2004,7 @@ public interface Frame {
*/
public WaitForSelectorState state;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -2031,7 +2031,7 @@ public interface Frame {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public WaitForSelectorOptions setStrict(boolean strict) {
@@ -2366,25 +2366,9 @@ public interface Frame {
* @param eventInit Optional event-specific initialization properties.
*/
void dispatchEvent(String selector, String type, Object eventInit, DispatchEventOptions options);
/**
*
*
* @param source A selector to search for an element to drag. If there are multiple elements satisfying the selector, the first will be
* used. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more details.
* @param target A selector to search for an element to drop onto. If there are multiple elements satisfying the selector, the first will
* be used. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more details.
*/
default void dragAndDrop(String source, String target) {
dragAndDrop(source, target, null);
}
/**
*
*
* @param source A selector to search for an element to drag. If there are multiple elements satisfying the selector, the first will be
* used. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more details.
* @param target A selector to search for an element to drop onto. If there are multiple elements satisfying the selector, the first will
* be used. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more details.
*/
void dragAndDrop(String source, String target, DragAndDropOptions options);
/**
* Returns the return value of {@code expression}.
@@ -30,7 +30,7 @@ import java.util.regex.Pattern;
* <p> **Strictness**
*
* <p> Frame locators are strict. This means that all operations on frame locators will throw if more than one element matches
* a given selector.
* given selector.
* <pre>{@code
* // Throws if there are several frames in DOM:
* page.frame_locator(".result-frame").locator("button").click();
@@ -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 overlaid with a pink box
* Specify locators that should be masked when the screenshot is taken. Masked elements will be overlayed 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 overlaid with a pink box
* Specify locators that should be masked when the screenshot is taken. Masked elements will be overlayed with a pink box
* {@code #FF00FF} that completely covers its bounding box.
*/
public ScreenshotOptions setMask(List<Locator> mask) {
@@ -1636,7 +1636,7 @@ public interface Locator {
* This method returns the bounding box of the element, or {@code null} if the element is not visible. The bounding box is
* calculated relative to the main frame viewport - which is usually the same as the browser window.
*
* <p> Scrolling affects the returned bounding box, similarly to <a
* <p> Scrolling affects the returned bonding box, similarly to <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect">Element.getBoundingClientRect</a>.
* That means {@code x} and/or {@code y} may be negative.
*
@@ -1657,7 +1657,7 @@ public interface Locator {
* This method returns the bounding box of the element, or {@code null} if the element is not visible. The bounding box is
* calculated relative to the main frame viewport - which is usually the same as the browser window.
*
* <p> Scrolling affects the returned bounding box, similarly to <a
* <p> Scrolling affects the returned bonding box, similarly to <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect">Element.getBoundingClientRect</a>.
* That means {@code x} and/or {@code y} may be negative.
*
@@ -428,7 +428,7 @@ public interface Page extends AutoCloseable {
*/
public Position position;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -478,7 +478,7 @@ public interface Page extends AutoCloseable {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public CheckOptions setStrict(boolean strict) {
@@ -539,7 +539,7 @@ public interface Page extends AutoCloseable {
*/
public Position position;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -618,7 +618,7 @@ public interface Page extends AutoCloseable {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public ClickOptions setStrict(boolean strict) {
@@ -691,7 +691,7 @@ public interface Page extends AutoCloseable {
*/
public Position position;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -763,7 +763,7 @@ public interface Page extends AutoCloseable {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public DblclickOptions setStrict(boolean strict) {
@@ -791,7 +791,7 @@ public interface Page extends AutoCloseable {
}
class DispatchEventOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -803,7 +803,7 @@ public interface Page extends AutoCloseable {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public DispatchEventOptions setStrict(boolean strict) {
@@ -838,7 +838,7 @@ public interface Page extends AutoCloseable {
*/
public Position sourcePosition;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -893,7 +893,7 @@ public interface Page extends AutoCloseable {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public DragAndDropOptions setStrict(boolean strict) {
@@ -943,6 +943,9 @@ public interface Page extends AutoCloseable {
/**
* Emulates {@code "forced-colors"} media feature, supported values are {@code "active"} and {@code "none"}. Passing {@code null} disables forced
* colors emulation.
*
* <p> <strong>NOTE:</strong> It's not supported in WebKit, see <a href="https://bugs.webkit.org/show_bug.cgi?id=225281">here</a> in their issue
* tracker.
*/
public Optional<ForcedColors> forcedColors;
/**
@@ -967,6 +970,9 @@ public interface Page extends AutoCloseable {
/**
* Emulates {@code "forced-colors"} media feature, supported values are {@code "active"} and {@code "none"}. Passing {@code null} disables forced
* colors emulation.
*
* <p> <strong>NOTE:</strong> It's not supported in WebKit, see <a href="https://bugs.webkit.org/show_bug.cgi?id=225281">here</a> in their issue
* tracker.
*/
public EmulateMediaOptions setForcedColors(ForcedColors forcedColors) {
this.forcedColors = Optional.ofNullable(forcedColors);
@@ -991,13 +997,13 @@ public interface Page extends AutoCloseable {
}
class EvalOnSelectorOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public EvalOnSelectorOptions setStrict(boolean strict) {
@@ -1034,7 +1040,7 @@ public interface Page extends AutoCloseable {
*/
public Boolean noWaitAfter;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1063,7 +1069,7 @@ public interface Page extends AutoCloseable {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public FillOptions setStrict(boolean strict) {
@@ -1082,7 +1088,7 @@ public interface Page extends AutoCloseable {
}
class FocusOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1094,7 +1100,7 @@ public interface Page extends AutoCloseable {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public FocusOptions setStrict(boolean strict) {
@@ -1113,7 +1119,7 @@ public interface Page extends AutoCloseable {
}
class GetAttributeOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1125,7 +1131,7 @@ public interface Page extends AutoCloseable {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public GetAttributeOptions setStrict(boolean strict) {
@@ -1301,7 +1307,7 @@ public interface Page extends AutoCloseable {
*/
public Position position;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1350,7 +1356,7 @@ public interface Page extends AutoCloseable {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public HoverOptions setStrict(boolean strict) {
@@ -1378,7 +1384,7 @@ public interface Page extends AutoCloseable {
}
class InnerHTMLOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1390,7 +1396,7 @@ public interface Page extends AutoCloseable {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public InnerHTMLOptions setStrict(boolean strict) {
@@ -1409,7 +1415,7 @@ public interface Page extends AutoCloseable {
}
class InnerTextOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1421,7 +1427,7 @@ public interface Page extends AutoCloseable {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public InnerTextOptions setStrict(boolean strict) {
@@ -1440,7 +1446,7 @@ public interface Page extends AutoCloseable {
}
class InputValueOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1452,7 +1458,7 @@ public interface Page extends AutoCloseable {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public InputValueOptions setStrict(boolean strict) {
@@ -1471,7 +1477,7 @@ public interface Page extends AutoCloseable {
}
class IsCheckedOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1483,7 +1489,7 @@ public interface Page extends AutoCloseable {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public IsCheckedOptions setStrict(boolean strict) {
@@ -1502,7 +1508,7 @@ public interface Page extends AutoCloseable {
}
class IsDisabledOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1514,7 +1520,7 @@ public interface Page extends AutoCloseable {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public IsDisabledOptions setStrict(boolean strict) {
@@ -1533,7 +1539,7 @@ public interface Page extends AutoCloseable {
}
class IsEditableOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1545,7 +1551,7 @@ public interface Page extends AutoCloseable {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public IsEditableOptions setStrict(boolean strict) {
@@ -1564,7 +1570,7 @@ public interface Page extends AutoCloseable {
}
class IsEnabledOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1576,7 +1582,7 @@ public interface Page extends AutoCloseable {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public IsEnabledOptions setStrict(boolean strict) {
@@ -1595,7 +1601,7 @@ public interface Page extends AutoCloseable {
}
class IsHiddenOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1606,7 +1612,7 @@ public interface Page extends AutoCloseable {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public IsHiddenOptions setStrict(boolean strict) {
@@ -1624,7 +1630,7 @@ public interface Page extends AutoCloseable {
}
class IsVisibleOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1635,7 +1641,7 @@ public interface Page extends AutoCloseable {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public IsVisibleOptions setStrict(boolean strict) {
@@ -1873,7 +1879,7 @@ public interface Page extends AutoCloseable {
*/
public Boolean noWaitAfter;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -1901,7 +1907,7 @@ public interface Page extends AutoCloseable {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public PressOptions setStrict(boolean strict) {
@@ -1920,13 +1926,13 @@ public interface Page extends AutoCloseable {
}
class QuerySelectorOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public QuerySelectorOptions setStrict(boolean strict) {
@@ -2007,7 +2013,7 @@ public interface Page extends AutoCloseable {
public Boolean update;
/**
* A glob pattern, regular expression or predicate to match the request URL. Only requests with URL matching the pattern
* will be served from the HAR file. If not specified, all requests are served from the HAR file.
* will be surved from the HAR file. If not specified, all requests are served from the HAR file.
*/
public Object url;
@@ -2032,7 +2038,7 @@ public interface Page extends AutoCloseable {
}
/**
* A glob pattern, regular expression or predicate to match the request URL. Only requests with URL matching the pattern
* will be served from the HAR file. If not specified, all requests are served from the HAR file.
* will be surved from the HAR file. If not specified, all requests are served from the HAR file.
*/
public RouteFromHAROptions setUrl(String url) {
this.url = url;
@@ -2040,7 +2046,7 @@ public interface Page extends AutoCloseable {
}
/**
* A glob pattern, regular expression or predicate to match the request URL. Only requests with URL matching the pattern
* will be served from the HAR file. If not specified, all requests are served from the HAR file.
* will be surved from the HAR file. If not specified, all requests are served from the HAR file.
*/
public RouteFromHAROptions setUrl(Pattern url) {
this.url = url;
@@ -2074,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 overlaid with a pink box
* Specify locators that should be masked when the screenshot is taken. Masked elements will be overlayed with a pink box
* {@code #FF00FF} that completely covers its bounding box.
*/
public List<Locator> mask;
@@ -2156,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 overlaid with a pink box
* Specify locators that should be masked when the screenshot is taken. Masked elements will be overlayed with a pink box
* {@code #FF00FF} that completely covers its bounding box.
*/
public ScreenshotOptions setMask(List<Locator> mask) {
@@ -2228,7 +2234,7 @@ public interface Page extends AutoCloseable {
*/
public Boolean noWaitAfter;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -2257,7 +2263,7 @@ public interface Page extends AutoCloseable {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public SelectOptionOptions setStrict(boolean strict) {
@@ -2292,7 +2298,7 @@ public interface Page extends AutoCloseable {
*/
public Position position;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -2342,7 +2348,7 @@ public interface Page extends AutoCloseable {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public SetCheckedOptions setStrict(boolean strict) {
@@ -2419,7 +2425,7 @@ public interface Page extends AutoCloseable {
*/
public Boolean noWaitAfter;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -2440,7 +2446,7 @@ public interface Page extends AutoCloseable {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public SetInputFilesOptions setStrict(boolean strict) {
@@ -2480,7 +2486,7 @@ public interface Page extends AutoCloseable {
*/
public Position position;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -2538,7 +2544,7 @@ public interface Page extends AutoCloseable {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public TapOptions setStrict(boolean strict) {
@@ -2566,7 +2572,7 @@ public interface Page extends AutoCloseable {
}
class TextContentOptions {
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -2578,7 +2584,7 @@ public interface Page extends AutoCloseable {
public Double timeout;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public TextContentOptions setStrict(boolean strict) {
@@ -2607,7 +2613,7 @@ public interface Page extends AutoCloseable {
*/
public Boolean noWaitAfter;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -2635,7 +2641,7 @@ public interface Page extends AutoCloseable {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public TypeOptions setStrict(boolean strict) {
@@ -2670,7 +2676,7 @@ public interface Page extends AutoCloseable {
*/
public Position position;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -2720,7 +2726,7 @@ public interface Page extends AutoCloseable {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public UncheckOptions setStrict(boolean strict) {
@@ -3070,7 +3076,7 @@ public interface Page extends AutoCloseable {
*/
public WaitForSelectorState state;
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public Boolean strict;
@@ -3097,7 +3103,7 @@ public interface Page extends AutoCloseable {
return this;
}
/**
* When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
* When true, the call requires selector to resolve to a single element. If given selector resolves to more then one
* element, the call throws an exception.
*/
public WaitForSelectorOptions setStrict(boolean strict) {
@@ -3575,25 +3581,9 @@ public interface Page extends AutoCloseable {
* @param eventInit Optional event-specific initialization properties.
*/
void dispatchEvent(String selector, String type, Object eventInit, DispatchEventOptions options);
/**
*
*
* @param source A selector to search for an element to drag. If there are multiple elements satisfying the selector, the first will be
* used. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more details.
* @param target A selector to search for an element to drop onto. If there are multiple elements satisfying the selector, the first will
* be used. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more details.
*/
default void dragAndDrop(String source, String target) {
dragAndDrop(source, target, null);
}
/**
*
*
* @param source A selector to search for an element to drag. If there are multiple elements satisfying the selector, the first will be
* used. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more details.
* @param target A selector to search for an element to drop onto. If there are multiple elements satisfying the selector, the first will
* be used. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more details.
*/
void dragAndDrop(String source, String target, DragAndDropOptions options);
/**
* This method changes the {@code CSS media type} through the {@code media} argument, and/or the {@code "prefers-colors-scheme"} media
@@ -6639,7 +6629,7 @@ public interface Page extends AutoCloseable {
* {@code detached}.
*
* <p> <strong>NOTE:</strong> Playwright automatically waits for element to be ready before performing an action. Using {@code Locator} objects and
* web-first assertions makes the code wait-for-selector-free.
* web-first assertions make the code wait-for-selector-free.
*
* <p> Wait for the {@code selector} to satisfy {@code state} option (either appear/disappear from dom, or become visible/hidden). If at
* the moment of calling the method {@code selector} already satisfies the condition, the method will return immediately. If the
@@ -6677,7 +6667,7 @@ public interface Page extends AutoCloseable {
* {@code detached}.
*
* <p> <strong>NOTE:</strong> Playwright automatically waits for element to be ready before performing an action. Using {@code Locator} objects and
* web-first assertions makes the code wait-for-selector-free.
* web-first assertions make the code wait-for-selector-free.
*
* <p> Wait for the {@code selector} to satisfy {@code state} option (either appear/disappear from dom, or become visible/hidden). If at
* the moment of calling the method {@code selector} already satisfies the condition, the method will return immediately. If the
@@ -40,7 +40,7 @@ public interface Response {
*/
Frame frame();
/**
* Indicates whether this Response was fulfilled by a Service Worker's Fetch Handler (i.e. via <a
* Indicates whether this Response was fullfilled 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();
@@ -280,7 +280,7 @@ public interface Route {
void resume(ResumeOptions options);
/**
* When several routes match the given pattern, they run in the order opposite to their registration. That way the last
* registered route can always override all the previous ones. In the example below, request will be handled by the
* registered route can always override all the previos ones. In the example below, request will be handled by the
* bottom-most handler first, then it'll fall back to the previous one and in the end will be aborted by the first
* registered route.
* <pre>{@code
@@ -341,7 +341,7 @@ public interface Route {
}
/**
* When several routes match the given pattern, they run in the order opposite to their registration. That way the last
* registered route can always override all the previous ones. In the example below, request will be handled by the
* registered route can always override all the previos ones. In the example below, request will be handled by the
* bottom-most handler first, then it'll fall back to the previous one and in the end will be aborted by the first
* registered route.
* <pre>{@code
@@ -44,7 +44,7 @@ public interface Selectors {
/**
* An example of registering selector engine that queries elements based on a tag name:
* <pre>{@code
* // Script that evaluates to a selector engine instance. The script is evaluated in the page context.
* // Script that evaluates to a selector engine instance.
* String createTagNameEngine = "{\n" +
* " // Returns the first element matching given selector in the root's subtree.\n" +
* " query(root, selector) {\n" +
@@ -63,7 +63,7 @@ public interface Selectors {
* // Use the selector prefixed with its name.
* Locator button = page.locator("tag=button");
* // Combine it with other selector engines.
* page.locator("tag=div >> text=\"Click me\"").click();
* page.click("tag=div >> text=\"Click me\"");
* // Can use it in any methods supporting selectors.
* int buttonCount = (int) page.locator("tag=button").count();
* browser.close();
@@ -71,7 +71,7 @@ public interface Selectors {
*
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May only
* contain {@code [a-zA-Z0-9_]} characters.
* @param script Script that evaluates to a selector engine instance. The script is evaluated in the page context.
* @param script Script that evaluates to a selector engine instance.
*/
default void register(String name, String script) {
register(name, script, null);
@@ -79,7 +79,7 @@ public interface Selectors {
/**
* An example of registering selector engine that queries elements based on a tag name:
* <pre>{@code
* // Script that evaluates to a selector engine instance. The script is evaluated in the page context.
* // Script that evaluates to a selector engine instance.
* String createTagNameEngine = "{\n" +
* " // Returns the first element matching given selector in the root's subtree.\n" +
* " query(root, selector) {\n" +
@@ -98,7 +98,7 @@ public interface Selectors {
* // Use the selector prefixed with its name.
* Locator button = page.locator("tag=button");
* // Combine it with other selector engines.
* page.locator("tag=div >> text=\"Click me\"").click();
* page.click("tag=div >> text=\"Click me\"");
* // Can use it in any methods supporting selectors.
* int buttonCount = (int) page.locator("tag=button").count();
* browser.close();
@@ -106,13 +106,13 @@ public interface Selectors {
*
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May only
* contain {@code [a-zA-Z0-9_]} characters.
* @param script Script that evaluates to a selector engine instance. The script is evaluated in the page context.
* @param script Script that evaluates to a selector engine instance.
*/
void register(String name, String script, RegisterOptions options);
/**
* An example of registering selector engine that queries elements based on a tag name:
* <pre>{@code
* // Script that evaluates to a selector engine instance. The script is evaluated in the page context.
* // Script that evaluates to a selector engine instance.
* String createTagNameEngine = "{\n" +
* " // Returns the first element matching given selector in the root's subtree.\n" +
* " query(root, selector) {\n" +
@@ -131,7 +131,7 @@ public interface Selectors {
* // Use the selector prefixed with its name.
* Locator button = page.locator("tag=button");
* // Combine it with other selector engines.
* page.locator("tag=div >> text=\"Click me\"").click();
* page.click("tag=div >> text=\"Click me\"");
* // Can use it in any methods supporting selectors.
* int buttonCount = (int) page.locator("tag=button").count();
* browser.close();
@@ -139,7 +139,7 @@ public interface Selectors {
*
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May only
* contain {@code [a-zA-Z0-9_]} characters.
* @param script Script that evaluates to a selector engine instance. The script is evaluated in the page context.
* @param script Script that evaluates to a selector engine instance.
*/
default void register(String name, Path script) {
register(name, script, null);
@@ -147,7 +147,7 @@ public interface Selectors {
/**
* An example of registering selector engine that queries elements based on a tag name:
* <pre>{@code
* // Script that evaluates to a selector engine instance. The script is evaluated in the page context.
* // Script that evaluates to a selector engine instance.
* String createTagNameEngine = "{\n" +
* " // Returns the first element matching given selector in the root's subtree.\n" +
* " query(root, selector) {\n" +
@@ -166,7 +166,7 @@ public interface Selectors {
* // Use the selector prefixed with its name.
* Locator button = page.locator("tag=button");
* // Combine it with other selector engines.
* page.locator("tag=div >> text=\"Click me\"").click();
* page.click("tag=div >> text=\"Click me\"");
* // Can use it in any methods supporting selectors.
* int buttonCount = (int) page.locator("tag=button").count();
* browser.close();
@@ -174,7 +174,7 @@ public interface Selectors {
*
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May only
* contain {@code [a-zA-Z0-9_]} characters.
* @param script Script that evaluates to a selector engine instance. The script is evaluated in the page context.
* @param script Script that evaluates to a selector engine instance.
*/
void register(String name, Path script, RegisterOptions options);
}
@@ -192,7 +192,7 @@ public interface Tracing {
* page.navigate("https://playwright.dev");
*
* context.tracing().startChunk();
* page.locator("text=Get Started").click();
* page.click("text=Get Started");
* // Everything between startChunk and stopChunk will be recorded in the trace.
* context.tracing().stopChunk(new Tracing.StopChunkOptions()
* .setPath(Paths.get("trace1.zip")));
@@ -219,7 +219,7 @@ public interface Tracing {
* page.navigate("https://playwright.dev");
*
* context.tracing().startChunk();
* page.locator("text=Get Started").click();
* page.click("text=Get Started");
* // Everything between startChunk and stopChunk will be recorded in the trace.
* context.tracing().stopChunk(new Tracing.StopChunkOptions()
* .setPath(Paths.get("trace1.zip")));
@@ -46,7 +46,7 @@ public interface APIResponseAssertions {
*/
APIResponseAssertions not();
/**
* Ensures the response status code is within {@code 200..299} range.
* Ensures the response status code is within [200..299] range.
* <pre>{@code
* assertThat(response).isOK();
* }</pre>
@@ -31,7 +31,7 @@ import java.util.regex.Pattern;
* @Test
* void statusBecomesSubmitted() {
* ...
* page.locator("#submit-button").click();
* page.click("#submit-button");
* assertThat(page.locator(".status")).hasText("Submitted");
* }
* }
@@ -72,16 +72,11 @@ public interface LocatorAssertions {
}
}
class IsEditableOptions {
public Boolean editable;
/**
* Time to retry the assertion for.
*/
public Double timeout;
public IsEditableOptions setEditable(boolean editable) {
this.editable = editable;
return this;
}
/**
* Time to retry the assertion for.
*/
@@ -105,16 +100,11 @@ public interface LocatorAssertions {
}
}
class IsEnabledOptions {
public Boolean enabled;
/**
* Time to retry the assertion for.
*/
public Double timeout;
public IsEnabledOptions setEnabled(boolean enabled) {
this.enabled = enabled;
return this;
}
/**
* Time to retry the assertion for.
*/
@@ -156,7 +146,6 @@ public interface LocatorAssertions {
* Time to retry the assertion for.
*/
public Double timeout;
public Boolean visible;
/**
* Time to retry the assertion for.
@@ -165,10 +154,6 @@ public interface LocatorAssertions {
this.timeout = timeout;
return this;
}
public IsVisibleOptions setVisible(boolean visible) {
this.visible = visible;
return this;
}
}
class ContainsTextOptions {
/**
@@ -471,8 +456,8 @@ public interface LocatorAssertions {
*/
void isFocused(IsFocusedOptions options);
/**
* Ensures that {@code Locator} either does not resolve to any DOM node, or resolves to a <a
* href="https://playwright.dev/java/docs/api/actionability#visible">non-visible</a> one.
* Ensures the {@code Locator} points to a hidden DOM node, which is the opposite of <a
* href="https://playwright.dev/java/docs/api/actionability#visible">visible</a>.
* <pre>{@code
* assertThat(page.locator(".my-element")).isHidden();
* }</pre>
@@ -481,16 +466,16 @@ public interface LocatorAssertions {
isHidden(null);
}
/**
* Ensures that {@code Locator} either does not resolve to any DOM node, or resolves to a <a
* href="https://playwright.dev/java/docs/api/actionability#visible">non-visible</a> one.
* Ensures the {@code Locator} points to a hidden DOM node, which is the opposite of <a
* href="https://playwright.dev/java/docs/api/actionability#visible">visible</a>.
* <pre>{@code
* assertThat(page.locator(".my-element")).isHidden();
* }</pre>
*/
void isHidden(IsHiddenOptions options);
/**
* Ensures that {@code Locator} points to an <a href="https://playwright.dev/java/docs/api/actionability#visible">attached</a>
* and <a href="https://playwright.dev/java/docs/api/actionability#visible">visible</a> DOM node.
* Ensures the {@code Locator} points to a <a href="https://playwright.dev/java/docs/api/actionability#visible">visible</a> DOM
* node.
* <pre>{@code
* assertThat(page.locator(".my-element")).isVisible();
* }</pre>
@@ -499,8 +484,8 @@ public interface LocatorAssertions {
isVisible(null);
}
/**
* Ensures that {@code Locator} points to an <a href="https://playwright.dev/java/docs/api/actionability#visible">attached</a>
* and <a href="https://playwright.dev/java/docs/api/actionability#visible">visible</a> DOM node.
* Ensures the {@code Locator} points to a <a href="https://playwright.dev/java/docs/api/actionability#visible">visible</a> DOM
* node.
* <pre>{@code
* assertThat(page.locator(".my-element")).isVisible();
* }</pre>
@@ -513,29 +498,9 @@ public interface LocatorAssertions {
* assertThat(page.locator(".title")).containsText("substring");
* }</pre>
*
* <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:
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
* <pre>{@code
* // ✓ 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"});
* assertThat(page.locator("list > .list-item")).containsText(new String[] {"Text 1", "Text 4", "Text 5"});
* }</pre>
*
* @param expected Expected substring or RegExp or a list of those.
@@ -550,29 +515,9 @@ public interface LocatorAssertions {
* assertThat(page.locator(".title")).containsText("substring");
* }</pre>
*
* <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:
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
* <pre>{@code
* // ✓ 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"});
* assertThat(page.locator("list > .list-item")).containsText(new String[] {"Text 1", "Text 4", "Text 5"});
* }</pre>
*
* @param expected Expected substring or RegExp or a list of those.
@@ -585,29 +530,9 @@ public interface LocatorAssertions {
* assertThat(page.locator(".title")).containsText("substring");
* }</pre>
*
* <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:
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
* <pre>{@code
* // ✓ 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"});
* assertThat(page.locator("list > .list-item")).containsText(new String[] {"Text 1", "Text 4", "Text 5"});
* }</pre>
*
* @param expected Expected substring or RegExp or a list of those.
@@ -622,29 +547,9 @@ public interface LocatorAssertions {
* assertThat(page.locator(".title")).containsText("substring");
* }</pre>
*
* <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:
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
* <pre>{@code
* // ✓ 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"});
* assertThat(page.locator("list > .list-item")).containsText(new String[] {"Text 1", "Text 4", "Text 5"});
* }</pre>
*
* @param expected Expected substring or RegExp or a list of those.
@@ -657,29 +562,9 @@ public interface LocatorAssertions {
* assertThat(page.locator(".title")).containsText("substring");
* }</pre>
*
* <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:
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
* <pre>{@code
* // ✓ 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"});
* assertThat(page.locator("list > .list-item")).containsText(new String[] {"Text 1", "Text 4", "Text 5"});
* }</pre>
*
* @param expected Expected substring or RegExp or a list of those.
@@ -694,29 +579,9 @@ public interface LocatorAssertions {
* assertThat(page.locator(".title")).containsText("substring");
* }</pre>
*
* <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:
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
* <pre>{@code
* // ✓ 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"});
* assertThat(page.locator("list > .list-item")).containsText(new String[] {"Text 1", "Text 4", "Text 5"});
* }</pre>
*
* @param expected Expected substring or RegExp or a list of those.
@@ -729,29 +594,9 @@ public interface LocatorAssertions {
* assertThat(page.locator(".title")).containsText("substring");
* }</pre>
*
* <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:
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
* <pre>{@code
* // ✓ 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"});
* assertThat(page.locator("list > .list-item")).containsText(new String[] {"Text 1", "Text 4", "Text 5"});
* }</pre>
*
* @param expected Expected substring or RegExp or a list of those.
@@ -766,29 +611,9 @@ public interface LocatorAssertions {
* assertThat(page.locator(".title")).containsText("substring");
* }</pre>
*
* <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:
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
* <pre>{@code
* // ✓ 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"});
* assertThat(page.locator("list > .list-item")).containsText(new String[] {"Text 1", "Text 4", "Text 5"});
* }</pre>
*
* @param expected Expected substring or RegExp or a list of those.
@@ -804,7 +629,7 @@ public interface LocatorAssertions {
* @param value Expected attribute value.
*/
default void hasAttribute(String name, String value) {
hasAttribute(name, value, (HasAttributeOptions) null);
hasAttribute(name, value, null);
}
/**
* Ensures the {@code Locator} points to an element with given attribute.
@@ -826,7 +651,7 @@ public interface LocatorAssertions {
* @param value Expected attribute value.
*/
default void hasAttribute(String name, Pattern value) {
hasAttribute(name, value, (HasAttributeOptions) null);
hasAttribute(name, value, null);
}
/**
* Ensures the {@code Locator} points to an element with given attribute.
@@ -839,11 +664,9 @@ public interface LocatorAssertions {
*/
void hasAttribute(String name, Pattern value, HasAttributeOptions options);
/**
* Ensures the {@code Locator} points to an element with given CSS classes. This needs to be a full match or using a relaxed
* regular expression.
* Ensures the {@code Locator} points to an element with given CSS class.
* <pre>{@code
* assertThat(page.locator("#component")).hasClass(Pattern.compile("selected"));
* assertThat(page.locator("#component")).hasClass("selected row");
* }</pre>
*
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
@@ -857,11 +680,9 @@ public interface LocatorAssertions {
hasClass(expected, null);
}
/**
* Ensures the {@code Locator} points to an element with given CSS classes. This needs to be a full match or using a relaxed
* regular expression.
* Ensures the {@code Locator} points to an element with given CSS class.
* <pre>{@code
* assertThat(page.locator("#component")).hasClass(Pattern.compile("selected"));
* assertThat(page.locator("#component")).hasClass("selected row");
* }</pre>
*
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
@@ -873,11 +694,9 @@ public interface LocatorAssertions {
*/
void hasClass(String expected, HasClassOptions options);
/**
* Ensures the {@code Locator} points to an element with given CSS classes. This needs to be a full match or using a relaxed
* regular expression.
* Ensures the {@code Locator} points to an element with given CSS class.
* <pre>{@code
* assertThat(page.locator("#component")).hasClass(Pattern.compile("selected"));
* assertThat(page.locator("#component")).hasClass("selected row");
* }</pre>
*
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
@@ -891,11 +710,9 @@ public interface LocatorAssertions {
hasClass(expected, null);
}
/**
* Ensures the {@code Locator} points to an element with given CSS classes. This needs to be a full match or using a relaxed
* regular expression.
* Ensures the {@code Locator} points to an element with given CSS class.
* <pre>{@code
* assertThat(page.locator("#component")).hasClass(Pattern.compile("selected"));
* assertThat(page.locator("#component")).hasClass("selected row");
* }</pre>
*
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
@@ -907,11 +724,9 @@ public interface LocatorAssertions {
*/
void hasClass(Pattern expected, HasClassOptions options);
/**
* Ensures the {@code Locator} points to an element with given CSS classes. This needs to be a full match or using a relaxed
* regular expression.
* Ensures the {@code Locator} points to an element with given CSS class.
* <pre>{@code
* assertThat(page.locator("#component")).hasClass(Pattern.compile("selected"));
* assertThat(page.locator("#component")).hasClass("selected row");
* }</pre>
*
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
@@ -925,11 +740,9 @@ public interface LocatorAssertions {
hasClass(expected, null);
}
/**
* Ensures the {@code Locator} points to an element with given CSS classes. This needs to be a full match or using a relaxed
* regular expression.
* Ensures the {@code Locator} points to an element with given CSS class.
* <pre>{@code
* assertThat(page.locator("#component")).hasClass(Pattern.compile("selected"));
* assertThat(page.locator("#component")).hasClass("selected row");
* }</pre>
*
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
@@ -941,11 +754,9 @@ public interface LocatorAssertions {
*/
void hasClass(String[] expected, HasClassOptions options);
/**
* Ensures the {@code Locator} points to an element with given CSS classes. This needs to be a full match or using a relaxed
* regular expression.
* Ensures the {@code Locator} points to an element with given CSS class.
* <pre>{@code
* assertThat(page.locator("#component")).hasClass(Pattern.compile("selected"));
* assertThat(page.locator("#component")).hasClass("selected row");
* }</pre>
*
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
@@ -959,11 +770,9 @@ public interface LocatorAssertions {
hasClass(expected, null);
}
/**
* Ensures the {@code Locator} points to an element with given CSS classes. This needs to be a full match or using a relaxed
* regular expression.
* Ensures the {@code Locator} points to an element with given CSS class.
* <pre>{@code
* assertThat(page.locator("#component")).hasClass(Pattern.compile("selected"));
* assertThat(page.locator("#component")).hasClass("selected row");
* }</pre>
*
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
@@ -1109,28 +918,9 @@ public interface LocatorAssertions {
* assertThat(page.locator(".title")).hasText(Pattern.compile("Welcome, .*"));
* }</pre>
*
* <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:
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
* <pre>{@code
* // ✓ 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"});
* assertThat(page.locator("list > .component")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
* }</pre>
*
* @param expected Expected substring or RegExp or a list of those.
@@ -1145,28 +935,9 @@ public interface LocatorAssertions {
* assertThat(page.locator(".title")).hasText(Pattern.compile("Welcome, .*"));
* }</pre>
*
* <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:
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
* <pre>{@code
* // ✓ 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"});
* assertThat(page.locator("list > .component")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
* }</pre>
*
* @param expected Expected substring or RegExp or a list of those.
@@ -1179,28 +950,9 @@ public interface LocatorAssertions {
* assertThat(page.locator(".title")).hasText(Pattern.compile("Welcome, .*"));
* }</pre>
*
* <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:
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
* <pre>{@code
* // ✓ 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"});
* assertThat(page.locator("list > .component")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
* }</pre>
*
* @param expected Expected substring or RegExp or a list of those.
@@ -1215,28 +967,9 @@ public interface LocatorAssertions {
* assertThat(page.locator(".title")).hasText(Pattern.compile("Welcome, .*"));
* }</pre>
*
* <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:
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
* <pre>{@code
* // ✓ 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"});
* assertThat(page.locator("list > .component")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
* }</pre>
*
* @param expected Expected substring or RegExp or a list of those.
@@ -1249,28 +982,9 @@ public interface LocatorAssertions {
* assertThat(page.locator(".title")).hasText(Pattern.compile("Welcome, .*"));
* }</pre>
*
* <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:
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
* <pre>{@code
* // ✓ 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"});
* assertThat(page.locator("list > .component")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
* }</pre>
*
* @param expected Expected substring or RegExp or a list of those.
@@ -1285,28 +999,9 @@ public interface LocatorAssertions {
* assertThat(page.locator(".title")).hasText(Pattern.compile("Welcome, .*"));
* }</pre>
*
* <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:
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
* <pre>{@code
* // ✓ 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"});
* assertThat(page.locator("list > .component")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
* }</pre>
*
* @param expected Expected substring or RegExp or a list of those.
@@ -1319,28 +1014,9 @@ public interface LocatorAssertions {
* assertThat(page.locator(".title")).hasText(Pattern.compile("Welcome, .*"));
* }</pre>
*
* <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:
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
* <pre>{@code
* // ✓ 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"});
* assertThat(page.locator("list > .component")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
* }</pre>
*
* @param expected Expected substring or RegExp or a list of those.
@@ -1355,28 +1031,9 @@ public interface LocatorAssertions {
* assertThat(page.locator(".title")).hasText(Pattern.compile("Welcome, .*"));
* }</pre>
*
* <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:
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
* <pre>{@code
* // ✓ 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"});
* assertThat(page.locator("list > .component")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
* }</pre>
*
* @param expected Expected substring or RegExp or a list of those.
@@ -31,7 +31,7 @@ import java.util.regex.Pattern;
* @Test
* void navigatesToLoginPage() {
* ...
* page.locator("#login").click();
* page.click("#login");
* assertThat(page).hasURL(Pattern.compile(".*\/login"));
* }
* }
@@ -120,7 +120,7 @@ public interface PageAssertions {
* assertThat(page).hasURL(".com");
* }</pre>
*
* @param urlOrRegExp Expected URL string or RegExp.
* @param urlOrRegExp Expected substring or RegExp.
*/
default void hasURL(String urlOrRegExp) {
hasURL(urlOrRegExp, null);
@@ -131,7 +131,7 @@ public interface PageAssertions {
* assertThat(page).hasURL(".com");
* }</pre>
*
* @param urlOrRegExp Expected URL string or RegExp.
* @param urlOrRegExp Expected substring or RegExp.
*/
void hasURL(String urlOrRegExp, HasURLOptions options);
/**
@@ -140,7 +140,7 @@ public interface PageAssertions {
* assertThat(page).hasURL(".com");
* }</pre>
*
* @param urlOrRegExp Expected URL string or RegExp.
* @param urlOrRegExp Expected substring or RegExp.
*/
default void hasURL(Pattern urlOrRegExp) {
hasURL(urlOrRegExp, null);
@@ -151,7 +151,7 @@ public interface PageAssertions {
* assertThat(page).hasURL(".com");
* }</pre>
*
* @param urlOrRegExp Expected URL string or RegExp.
* @param urlOrRegExp Expected substring or RegExp.
*/
void hasURL(Pattern urlOrRegExp, HasURLOptions options);
}
@@ -20,7 +20,6 @@ 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;
@@ -38,7 +37,7 @@ import com.microsoft.playwright.impl.PageAssertionsImpl;
* @Test
* void statusBecomesSubmitted() {
* ...
* page.locator("#submit-button").click();
* page.click("#submit-button");
* assertThat(page.locator(".status")).hasText("Submitted");
* }
* }
@@ -87,17 +86,5 @@ 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);
}
}
@@ -110,12 +110,6 @@ class APIRequestContextImpl extends ChannelOwner implements APIRequestContext {
if (options.ignoreHTTPSErrors != null) {
params.addProperty("ignoreHTTPSErrors", options.ignoreHTTPSErrors);
}
if (options.maxRedirects != null) {
if (options.maxRedirects < 0) {
throw new PlaywrightException("'maxRedirects' should be greater than or equal to '0'");
}
params.addProperty("maxRedirects", options.maxRedirects);
}
JsonObject json = sendMessage("fetch", params).getAsJsonObject();
return new APIResponseImpl(this, json.getAsJsonObject("response"));
}
@@ -21,7 +21,6 @@ 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;
@@ -55,20 +54,6 @@ public class APIResponseAssertionsImpl implements APIResponseAssertions {
if (!log.isEmpty()) {
log = "\nCall log:\n" + 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);
throw new AssertionFailedError(message + log);
}
}
@@ -52,7 +52,7 @@ class AssertionsBase {
void expectImpl(String expression, FrameExpectOptions expectOptions, Object expected, String message) {
if (expectOptions.timeout == null) {
expectOptions.timeout = AssertionsTimeout.defaultTimeout;
expectOptions.timeout = 5_000.0;
}
if (expectOptions.isNot) {
message = message.replace("expected to", "expected not to");
@@ -1,30 +0,0 @@
/*
* 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;
}
}
@@ -36,6 +36,7 @@ import java.util.regex.Pattern;
import static com.microsoft.playwright.impl.Serialization.addHarUrlFilter;
import static com.microsoft.playwright.impl.Serialization.gson;
import static com.microsoft.playwright.impl.Utils.isSafeCloseError;
import static com.microsoft.playwright.impl.Utils.toJsRegexFlags;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.nio.file.Files.readAllBytes;
import static java.util.Arrays.asList;
@@ -83,7 +84,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("requestContext").get("guid").getAsString());
this.request = connection.getExistingObject(initializer.getAsJsonObject("APIRequestContext").get("guid").getAsString());
}
void setRecordHar(Path path, HarContentPolicy policy) {
@@ -170,7 +171,7 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
@Override
public Page waitForPage(WaitForPageOptions options, Runnable code) {
return withWaitLogging("BrowserContext.close", logger -> waitForPageImpl(options, code));
return withWaitLogging("BrowserContext.close", () -> waitForPageImpl(options, code));
}
private Page waitForPageImpl(WaitForPageOptions options, Runnable code) {
@@ -85,7 +85,7 @@ class BrowserTypeImpl extends ChannelOwner implements BrowserType {
JsonObject json = sendMessage("connect", params).getAsJsonObject();
JsonPipe pipe = connection.getExistingObject(json.getAsJsonObject("pipe").get("guid").getAsString());
Connection connection = new Connection(pipe, this.connection.env);
Connection connection = new Connection(pipe);
PlaywrightImpl playwright = connection.initializePlaywright();
if (!playwright.initializer.has("preLaunchedBrowser")) {
try {
@@ -22,13 +22,11 @@ import com.google.gson.JsonObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
class ChannelOwner extends LoggingSupport {
final Connection connection;
private ChannelOwner parent;
private final ChannelOwner parent;
private final Map<String, ChannelOwner> objects = new HashMap<>();
final String type;
@@ -70,13 +68,7 @@ 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, Function<Logger, T> code) {
<T> T withWaitLogging(String apiName, Supplier<T> code) {
return new WaitForEventLogger<>(this, apiName, code).get();
}
@@ -65,7 +65,6 @@ public class Connection {
isLogging = (debug != null) && debug.contains("pw:channel");
}
LocalUtils localUtils;
final Map<String, String> env;
class Root extends ChannelOwner {
Root(Connection connection) {
@@ -80,14 +79,13 @@ public class Connection {
}
}
Connection(Transport transport, Map<String, String> env) {
this.env = env;
Connection(Transport transport) {
if (isLogging) {
transport = new TransportLogger(transport);
}
this.transport = transport;
root = new Root(this);
stackTraceCollector = StackTraceCollector.createFromEnv(env);
stackTraceCollector = StackTraceCollector.createFromEnv();
}
boolean isCollectingStacks() {
@@ -201,24 +199,18 @@ 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);
}
@@ -811,17 +811,17 @@ public class FrameImpl extends ChannelOwner implements Frame {
@Override
public void waitForLoadState(LoadState state, WaitForLoadStateOptions options) {
withWaitLogging("Frame.waitForLoadState", logger -> {
waitForLoadStateImpl(state, options, logger);
withWaitLogging("Frame.waitForLoadState", () -> {
waitForLoadStateImpl(state, options);
return null;
});
}
void waitForLoadStateImpl(LoadState state, WaitForLoadStateOptions options, Logger logger) {
waitForLoadStateImpl(convertType(state, WaitUntilState.class), options, logger);
void waitForLoadStateImpl(LoadState state, WaitForLoadStateOptions options) {
waitForLoadStateImpl(convertType(state, WaitUntilState.class), options);
}
private void waitForLoadStateImpl(WaitUntilState state, WaitForLoadStateOptions options, Logger logger) {
private void waitForLoadStateImpl(WaitUntilState state, WaitForLoadStateOptions options) {
if (options == null) {
options = new WaitForLoadStateOptions();
}
@@ -830,7 +830,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
}
List<Waitable<Void>> waitables = new ArrayList<>();
waitables.add(new WaitForLoadStateHelper(state, logger));
waitables.add(new WaitForLoadStateHelper(state));
waitables.add(page.createWaitForCloseHelper());
waitables.add(page.createWaitableTimeout(options.timeout));
runUntil(() -> {}, new WaitableRace<>(waitables));
@@ -838,12 +838,10 @@ public class FrameImpl extends ChannelOwner implements Frame {
private class WaitForLoadStateHelper implements Waitable<Void>, Consumer<WaitUntilState> {
private final WaitUntilState expectedState;
private final Logger logger;
private boolean isDone;
WaitForLoadStateHelper(WaitUntilState state, Logger logger) {
WaitForLoadStateHelper(WaitUntilState state) {
expectedState = state;
this.logger = logger;
isDone = loadStates.contains(state);
if (!isDone) {
internalListeners.add(InternalEventType.LOADSTATE, this);
@@ -852,7 +850,6 @@ public class FrameImpl extends ChannelOwner implements Frame {
@Override
public void accept(WaitUntilState state) {
logger.log(" load state changed to " + state);
if (expectedState.equals(state)) {
isDone = true;
dispose();
@@ -876,24 +873,20 @@ public class FrameImpl extends ChannelOwner implements Frame {
private class WaitForNavigationHelper implements Waitable<Response>, Consumer<JsonObject> {
private final UrlMatcher matcher;
private final WaitUntilState expectedLoadState;
private final Logger logger;
private WaitForLoadStateHelper loadStateHelper;
private RequestImpl request;
private RuntimeException exception;
WaitForNavigationHelper(UrlMatcher matcher, WaitUntilState expectedLoadState, Logger logger) {
WaitForNavigationHelper(UrlMatcher matcher, WaitUntilState expectedLoadState) {
this.matcher = matcher;
this.expectedLoadState = expectedLoadState;
this.logger = logger;
internalListeners.add(InternalEventType.NAVIGATED, this);
}
@Override
public void accept(JsonObject params) {
String url = params.get("url").getAsString();
logger.log(" navigated to " + url);
if (!matcher.test(url)) {
if (!matcher.test(params.get("url").getAsString())) {
return;
}
if (params.has("error")) {
@@ -905,7 +898,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
request = connection.getExistingObject(jsonReq.get("guid").getAsString());
}
}
loadStateHelper = new WaitForLoadStateHelper(expectedLoadState, logger);
loadStateHelper = new WaitForLoadStateHelper(expectedLoadState);
}
internalListeners.remove(InternalEventType.NAVIGATED, this);
}
@@ -944,14 +937,14 @@ public class FrameImpl extends ChannelOwner implements Frame {
@Override
public Response waitForNavigation(WaitForNavigationOptions options, Runnable code) {
return withWaitLogging("Frame.waitForNavigation", logger -> waitForNavigationImpl(logger, code, options, null));
return withLogging("Frame.waitForNavigation", () -> waitForNavigationImpl(code, options, null));
}
Response waitForNavigationImpl(Logger logger, Runnable code, WaitForNavigationOptions options) {
return waitForNavigationImpl(logger, code, options, null);
Response waitForNavigationImpl(Runnable code, WaitForNavigationOptions options) {
return waitForNavigationImpl(code, options, null);
}
private Response waitForNavigationImpl(Logger logger, Runnable code, WaitForNavigationOptions options, UrlMatcher matcher) {
private Response waitForNavigationImpl(Runnable code, WaitForNavigationOptions options, UrlMatcher matcher) {
if (options == null) {
options = new WaitForNavigationOptions();
}
@@ -963,8 +956,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
if (matcher == null) {
matcher = UrlMatcher.forOneOf(page.context().baseUrl, options.url);
}
logger.log("waiting for navigation " + matcher);
waitables.add(new WaitForNavigationHelper(matcher, options.waitUntil, logger));
waitables.add(new WaitForNavigationHelper(matcher, options.waitUntil));
waitables.add(page.createWaitForCloseHelper());
waitables.add(page.createWaitableFrameDetach(this));
waitables.add(page.createWaitableNavigationTimeout(options.timeout));
@@ -1022,22 +1014,18 @@ public class FrameImpl extends ChannelOwner implements Frame {
}
private void waitForURL(UrlMatcher matcher, WaitForURLOptions options) {
withWaitLogging("Frame.waitForURL", logger -> {
waitForURLImpl(logger, matcher, options);
return null;
});
withLogging("Frame.waitForURL", () -> waitForURLImpl(matcher, options));
}
void waitForURLImpl(Logger logger, UrlMatcher matcher, WaitForURLOptions options) {
logger.log("waiting for url " + matcher);
void waitForURLImpl(UrlMatcher matcher, WaitForURLOptions options) {
if (options == null) {
options = new WaitForURLOptions();
}
if (matcher.test(url())) {
waitForLoadStateImpl(options.waitUntil, convertType(options, WaitForLoadStateOptions.class), logger);
waitForLoadStateImpl(options.waitUntil, convertType(options, WaitForLoadStateOptions.class));
return;
}
waitForNavigationImpl(logger, () -> {}, convertType(options, WaitForNavigationOptions.class), matcher);
waitForNavigationImpl(() -> {}, convertType(options, WaitForNavigationOptions.class), matcher);
}
int queryCount(String selector) {
@@ -26,7 +26,7 @@ import java.nio.file.Path;
import java.util.Base64;
import java.util.Map;
import static com.microsoft.playwright.impl.LoggingSupport.*;
import static com.microsoft.playwright.impl.LoggingSupport.logApi;
import static com.microsoft.playwright.impl.Serialization.fromNameValues;
import static com.microsoft.playwright.impl.Serialization.gson;
@@ -66,7 +66,7 @@ public class HARRouter {
String action = response.get("action").getAsString();
if ("redirect".equals(action)) {
String redirectURL = response.get("redirectURL").getAsString();
logApiIfEnabled("HAR: " + route.request().url() + " redirected to " + redirectURL);
logApi("HAR: " + route.request().url() + " redirected to " + redirectURL);
((RouteImpl) route).redirectNavigationRequest(redirectURL);
return;
}
@@ -83,7 +83,7 @@ public class HARRouter {
}
if ("error".equals(action)) {
logApiIfEnabled("HAR: " + response.get("message").getAsString());
logApi("HAR: " + response.get("message").getAsString());
// Report the error, but fall through to the default handler.
}
@@ -299,9 +299,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
@Override
public void isEditable(IsEditableOptions options) {
FrameExpectOptions frameOptions = convertType(options, FrameExpectOptions.class);
boolean editable = options == null || options.editable == null || options.editable == true;
expectTrue(editable ? "to.be.editable" : "to.be.readonly", "Locator expected to be editable", frameOptions);
expectTrue("to.be.editable", "Locator expected to be editable", convertType(options, FrameExpectOptions.class));
}
@Override
@@ -311,9 +309,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
@Override
public void isEnabled(IsEnabledOptions options) {
FrameExpectOptions frameOptions = convertType(options, FrameExpectOptions.class);
boolean enabled = options == null || options.enabled == null || options.enabled == true;
expectTrue(enabled ? "to.be.enabled" : "to.be.disabled", "Locator expected to be enabled", frameOptions);
expectTrue("to.be.enabled", "Locator expected to be enabled", convertType(options, FrameExpectOptions.class));
}
@Override
@@ -328,9 +324,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
@Override
public void isVisible(IsVisibleOptions options) {
FrameExpectOptions frameOptions = convertType(options, FrameExpectOptions.class);
boolean visible = options == null || options.visible == null || options.visible == true;
expectTrue(visible ? "to.be.visible" : "to.be.hidden", "Locator expected to be visible", frameOptions);
expectTrue("to.be.visible", "Locator expected to be visible", convertType(options, FrameExpectOptions.class));
}
private void expectTrue(String expression, String message, FrameExpectOptions options) {
@@ -67,8 +67,7 @@ class LocatorImpl implements Locator {
if (options.hasText != null) {
if (options.hasText instanceof Pattern) {
Pattern pattern = (Pattern) options.hasText;
String jsRegex = "/" + pattern.pattern() + "/" + toJsRegexFlags(pattern);
selector += " >> has=" + gson().toJson("text=" + jsRegex);
selector += " >> :scope:text-matches(" + escapeWithQuotes(pattern.pattern()) + ", \"" + toJsRegexFlags(pattern) + "\")";
} else if (options.hasText instanceof String) {
String text = (String) options.hasText;
selector += " >> :scope:has-text(" + escapeWithQuotes(text) + ")";
@@ -1,21 +0,0 @@
/*
* 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;
interface Logger {
void log(String message);
}
@@ -60,12 +60,6 @@ class LoggingSupport {
System.err.println(timestamp + " " + message);
}
static void logApiIfEnabled(String message) {
if (isEnabled) {
logApi(message);
}
}
static void logApi(String message) {
// This matches log format produced by the server.
logWithTimestamp("pw:api " + message);
@@ -443,7 +443,7 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public Page waitForClose(WaitForCloseOptions options, Runnable code) {
return withWaitLogging("Page.waitForClose", logger -> waitForCloseImpl(options, code));
return withWaitLogging("Page.waitForClose", () -> waitForCloseImpl(options, code));
}
private Page waitForCloseImpl(WaitForCloseOptions options, Runnable code) {
@@ -455,7 +455,7 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public ConsoleMessage waitForConsoleMessage(WaitForConsoleMessageOptions options, Runnable code) {
return withWaitLogging("Page.waitForConsoleMessage", logger -> waitForConsoleMessageImpl(options, code));
return withWaitLogging("Page.waitForConsoleMessage", () -> waitForConsoleMessageImpl(options, code));
}
private ConsoleMessage waitForConsoleMessageImpl(WaitForConsoleMessageOptions options, Runnable code) {
@@ -467,7 +467,7 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public Download waitForDownload(WaitForDownloadOptions options, Runnable code) {
return withWaitLogging("Page.waitForDownload", logger -> waitForDownloadImpl(options, code));
return withWaitLogging("Page.waitForDownload", () -> waitForDownloadImpl(options, code));
}
private Download waitForDownloadImpl(WaitForDownloadOptions options, Runnable code) {
@@ -479,7 +479,7 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public FileChooser waitForFileChooser(WaitForFileChooserOptions options, Runnable code) {
return withWaitLogging("Page.waitForFileChooser", logger -> waitForFileChooserImpl(options, code));
return withWaitLogging("Page.waitForFileChooser", () -> waitForFileChooserImpl(options, code));
}
private FileChooser waitForFileChooserImpl(WaitForFileChooserOptions options, Runnable code) {
@@ -492,7 +492,7 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public Page waitForPopup(WaitForPopupOptions options, Runnable code) {
return withWaitLogging("Page.waitForPopup", logger -> waitForPopupImpl(options, code));
return withWaitLogging("Page.waitForPopup", () -> waitForPopupImpl(options, code));
}
private Page waitForPopupImpl(WaitForPopupOptions options, Runnable code) {
@@ -504,7 +504,7 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public WebSocket waitForWebSocket(WaitForWebSocketOptions options, Runnable code) {
return withWaitLogging("Page.waitForWebSocket", logger -> waitForWebSocketImpl(options, code));
return withWaitLogging("Page.waitForWebSocket", () -> waitForWebSocketImpl(options, code));
}
private WebSocket waitForWebSocketImpl(WaitForWebSocketOptions options, Runnable code) {
@@ -516,7 +516,7 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public Worker waitForWorker(WaitForWorkerOptions options, Runnable code) {
return withWaitLogging("Page.waitForWorker", logger -> waitForWorkerImpl(options, code));
return withWaitLogging("Page.waitForWorker", () -> waitForWorkerImpl(options, code));
}
private Worker waitForWorkerImpl(WaitForWorkerOptions options, Runnable code) {
@@ -1268,25 +1268,25 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public void waitForLoadState(LoadState state, WaitForLoadStateOptions options) {
withWaitLogging("Page.waitForLoadState", logger -> {
mainFrame.waitForLoadStateImpl(state, convertType(options, Frame.WaitForLoadStateOptions.class), logger);
withWaitLogging("Page.waitForLoadState", () -> {
mainFrame.waitForLoadStateImpl(state, convertType(options, Frame.WaitForLoadStateOptions.class));
return null;
});
}
@Override
public Response waitForNavigation(WaitForNavigationOptions options, Runnable code) {
return withWaitLogging("Page.waitForNavigation", logger -> waitForNavigationImpl(logger, code, options));
return withLogging("Page.waitForNavigation", () -> waitForNavigationImpl(code, options));
}
private Response waitForNavigationImpl(Logger logger, Runnable code, WaitForNavigationOptions options) {
Response waitForNavigationImpl(Runnable code, WaitForNavigationOptions options) {
Frame.WaitForNavigationOptions frameOptions = new Frame.WaitForNavigationOptions();
if (options != null) {
frameOptions.timeout = options.timeout;
frameOptions.waitUntil = options.waitUntil;
frameOptions.url = options.url;
}
return mainFrame.waitForNavigationImpl(logger, code, frameOptions);
return mainFrame.waitForNavigationImpl(code, frameOptions);
}
void frameNavigated(FrameImpl frame) {
@@ -1338,28 +1338,21 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public Request waitForRequest(String urlGlob, WaitForRequestOptions options, Runnable code) {
return waitForRequest(new UrlMatcher(browserContext.baseUrl, urlGlob), null, options, code);
return waitForRequest(toRequestPredicate(new UrlMatcher(browserContext.baseUrl, urlGlob)), options, code);
}
@Override
public Request waitForRequest(Pattern urlPattern, WaitForRequestOptions options, Runnable code) {
return waitForRequest(new UrlMatcher(urlPattern), null, options, code);
return waitForRequest(toRequestPredicate(new UrlMatcher(urlPattern)), options, code);
}
@Override
public Request waitForRequest(Predicate<Request> predicate, WaitForRequestOptions options, Runnable code) {
return waitForRequest(null, predicate, options, code);
return withWaitLogging("Page.waitForRequest", () -> waitForRequestImpl(predicate, options, code));
}
private Request waitForRequest(UrlMatcher urlMatcher, Predicate<Request> predicate, WaitForRequestOptions options, Runnable code) {
return withWaitLogging("Page.waitForRequest", logger -> {
logger.log("waiting for request " + ((urlMatcher == null) ? "matching predicate" : urlMatcher.toString()));
Predicate<Request> requestPredicate = predicate;
if (requestPredicate == null) {
requestPredicate = request -> urlMatcher.test(request.url());;
}
return waitForRequestImpl(requestPredicate, options, code);
});
private static Predicate<Request> toRequestPredicate(UrlMatcher matcher) {
return request -> matcher.test(request.url());
}
private Request waitForRequestImpl(Predicate<Request> predicate, WaitForRequestOptions options, Runnable code) {
@@ -1371,7 +1364,7 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public Request waitForRequestFinished(WaitForRequestFinishedOptions options, Runnable code) {
return withWaitLogging("Page.waitForRequestFinished", logger -> waitForRequestFinishedImpl(options, code));
return withWaitLogging("Page.waitForRequestFinished", () -> waitForRequestFinishedImpl(options, code));
}
private Request waitForRequestFinishedImpl(WaitForRequestFinishedOptions options, Runnable code) {
@@ -1383,28 +1376,21 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public Response waitForResponse(String urlGlob, WaitForResponseOptions options, Runnable code) {
return waitForResponse(new UrlMatcher(browserContext.baseUrl, urlGlob), null, options, code);
return waitForResponse(toResponsePredicate(new UrlMatcher(browserContext.baseUrl, urlGlob)), options, code);
}
@Override
public Response waitForResponse(Pattern urlPattern, WaitForResponseOptions options, Runnable code) {
return waitForResponse(new UrlMatcher(urlPattern), null, options, code);
return waitForResponse(toResponsePredicate(new UrlMatcher(urlPattern)), options, code);
}
@Override
public Response waitForResponse(Predicate<Response> predicate, WaitForResponseOptions options, Runnable code) {
return waitForResponse(null, predicate, options, code);
return withLogging("Page.waitForResponse", () -> waitForResponseImpl(predicate, options, code));
}
private Response waitForResponse(UrlMatcher urlMatcher, Predicate<Response> predicate, WaitForResponseOptions options, Runnable code) {
return withWaitLogging("Page.waitForResponse", logger -> {
logger.log("waiting for response " + ((urlMatcher == null) ? "matching predicate" : urlMatcher.toString()));
Predicate<Response> responsePredicate = predicate;
if (responsePredicate == null) {
responsePredicate = response -> urlMatcher.test(response.url());;
}
return waitForResponseImpl(responsePredicate, options, code);
});
private static Predicate<Response> toResponsePredicate(UrlMatcher matcher) {
return response -> matcher.test(response.url());
}
private Response waitForResponseImpl(Predicate<Response> predicate, WaitForResponseOptions options, Runnable code) {
@@ -1441,10 +1427,7 @@ public class PageImpl extends ChannelOwner implements Page {
}
private void waitForURL(UrlMatcher matcher, WaitForURLOptions options) {
withWaitLogging("Page.waitForURL", logger -> {
mainFrame.waitForURLImpl(logger, matcher, convertType(options, Frame.WaitForURLOptions.class));
return null;
});
withLogging("Page.waitForURL", () -> mainFrame.waitForURLImpl(matcher, convertType(options, Frame.WaitForURLOptions.class)));
}
@Override
@@ -21,9 +21,9 @@ 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;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@@ -32,23 +32,18 @@ public class PlaywrightImpl extends ChannelOwner implements Playwright {
private Process driverProcess;
public static PlaywrightImpl create(CreateOptions options) {
return createImpl(options, false);
}
public static PlaywrightImpl createImpl(CreateOptions options, boolean forceNewDriverInstanceForTests) {
Map<String, String> env = Collections.emptyMap();
if (options != null && options.env != null) {
env = options.env;
}
Driver driver = forceNewDriverInstanceForTests ?
Driver.createAndInstall(env, true) :
Driver.ensureDriverInstalled(env, true);
try {
ProcessBuilder pb = driver.createProcessBuilder();
pb.command().add("run-driver");
Map<String, String> env = Collections.emptyMap();
if (options != null && options.env != null) {
env = options.env;
}
Path driver = Driver.ensureDriverInstalled(env, true);
ProcessBuilder pb = new ProcessBuilder(driver.toString(), "run-driver");
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
pb.environment().putAll(env);
Driver.setRequiredEnvironmentVariables(pb);
Process p = pb.start();
Connection connection = new Connection(new PipeTransport(p.getInputStream(), p.getOutputStream()), env);
Connection connection = new Connection(new PipeTransport(p.getInputStream(), p.getOutputStream()));
PlaywrightImpl result = connection.initializePlaywright();
result.driverProcess = p;
result.initSharedSelectors(null);
@@ -31,7 +31,6 @@ class SerializedValue{
// Possible values: { 'null, 'undefined, 'NaN, 'Infinity, '-Infinity, '-0 }
String v;
String d;
String u;
public static class R {
String p;
String f;
@@ -32,7 +32,6 @@ public class RequestOptionsImpl implements RequestOptions {
Boolean failOnStatusCode;
Boolean ignoreHTTPSErrors;
Double timeout;
Integer maxRedirects;
@Override
public RequestOptions setHeader(String name, String value) {
@@ -119,10 +118,4 @@ public class RequestOptionsImpl implements RequestOptions {
this.ignoreHTTPSErrors = ignoreHTTPSErrors;
return this;
}
@Override
public RequestOptions setMaxRedirects(int maxRedirects) {
this.maxRedirects = maxRedirects;
return this;
}
}
@@ -31,12 +31,10 @@ import java.util.Map;
import static com.microsoft.playwright.impl.Utils.convertType;
public class RouteImpl extends ChannelOwner implements Route {
private final RequestImpl request;
private boolean handled;
public RouteImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
super(parent, type, guid, initializer);
request = connection.getExistingObject(initializer.getAsJsonObject("request").get("guid").getAsString());
}
@Override
@@ -198,7 +196,7 @@ public class RouteImpl extends ChannelOwner implements Route {
@Override
public RequestImpl request() {
return request;
return connection.getExistingObject(initializer.getAsJsonObject("request").get("guid").getAsString());
}
void redirectNavigationRequest(String redirectURL) {
@@ -38,16 +38,22 @@ class Router {
this.times = times;
}
void handle(RouteImpl route) {
handler.accept(route);
}
boolean decrementRemainingCallCount() {
if (times == null) {
boolean handle(RouteImpl route) {
if (times != null && times <= 0) {
return false;
}
--times;
return times <= 0;
if (!matcher.test(route.request().url())) {
return false;
}
if (times != null) {
--times;
}
handler.accept(route);
return true;
}
boolean isDone() {
return times != null && times <= 0;
}
}
@@ -70,16 +76,14 @@ class Router {
HandleResult result = HandleResult.NoMatchingHandler;
for (Iterator<RouteInfo> it = routes.iterator(); it.hasNext();) {
RouteInfo info = it.next();
if (!info.matcher.test(route.request().url())) {
continue;
}
if (info.decrementRemainingCallCount()) {
it.remove();
}
result = HandleResult.FoundMatchingHandler;
info.handle(route);
if (route.isHandled()) {
break;
if (info.handle(route)) {
result = HandleResult.FoundMatchingHandler;
if (info.isDone()) {
it.remove();
}
if (route.isHandled()) {
break;
}
}
}
return result;
@@ -28,21 +28,15 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Type;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.regex.Pattern;
import static com.microsoft.playwright.impl.Utils.toJsRegexFlags;
import static com.microsoft.playwright.impl.Utils.fromJsRegexFlags;
class Serialization {
private static final Gson gson = new GsonBuilder().disableHtmlEscaping()
private static final Gson gson = new GsonBuilder()
.registerTypeAdapter(SameSiteAttribute.class, new SameSiteAdapter().nullSafe())
.registerTypeAdapter(BrowserChannel.class, new ToLowerCaseAndDashSerializer<BrowserChannel>())
.registerTypeAdapter(ColorScheme.class, new ToLowerCaseAndDashSerializer<ColorScheme>())
@@ -150,16 +144,6 @@ class Serialization {
result.n = (Integer) value;
} else if (value instanceof String) {
result.s = (String) value;
} else if (value instanceof Date) {
result.d = ((Date)value).toInstant().toString();
} else if (value instanceof LocalDateTime) {
result.d = ((LocalDateTime)value).atZone(ZoneId.systemDefault()).toInstant().toString();
} else if (value instanceof URL) {
result.u = ((URL)value).toString();
} else if (value instanceof Pattern) {
result.r = new SerializedValue.R();
result.r.p = ((Pattern)value).pattern();
result.r.f = toJsRegexFlags(((Pattern)value));
} else {
HashableValue mapKey = new HashableValue(value);
Integer id = valueToId.get(mapKey);
@@ -223,17 +207,6 @@ class Serialization {
return (T) value.b;
if (value.s != null)
return (T) value.s;
if (value.u != null) {
try {
return (T)(new URL(value.u));
} catch (MalformedURLException e) {
throw new PlaywrightException("Unexpected value: " + value.u, e);
}
}
if (value.d != null)
return (T)(Date.from(Instant.parse(value.d)));
if (value.r != null)
return (T)(Pattern.compile(value.r.p, fromJsRegexFlags(value.r.f)));
if (value.v != null) {
switch (value.v) {
case "undefined":
@@ -28,25 +28,18 @@ import java.util.*;
import java.util.stream.Collectors;
class StackTraceCollector {
static final String PLAYWRIGHT_JAVA_SRC = "PLAYWRIGHT_JAVA_SRC";
private final List<Path> srcDirs;
private final Map<Path, String> classToSourceCache = new HashMap<>();
static StackTraceCollector createFromEnv(Map<String, String> env) {
String srcRoots = null;
if (env != null) {
srcRoots = env.get(PLAYWRIGHT_JAVA_SRC);
}
if (srcRoots == null) {
srcRoots = System.getenv(PLAYWRIGHT_JAVA_SRC);
}
static StackTraceCollector createFromEnv() {
String srcRoots = System.getenv("PLAYWRIGHT_JAVA_SRC");
if (srcRoots == null) {
return null;
}
List<Path> srcDirs = Arrays.stream(srcRoots.split(File.pathSeparator)).map(p -> Paths.get(p)).collect(Collectors.toList());
for (Path srcDir: srcDirs) {
if (!Files.exists(srcDir.toAbsolutePath())) {
throw new PlaywrightException("Source location specified in " + PLAYWRIGHT_JAVA_SRC + " doesn't exist: '" + srcDir.toAbsolutePath() + "'");
throw new PlaywrightException("Source location specified in PLAYWRIGHT_JAVA_SRC doesn't exist: '" + srcDir.toAbsolutePath() + "'");
}
}
return new StackTraceCollector(srcDirs);
@@ -97,13 +97,4 @@ class UrlMatcher {
public int hashCode() {
return Objects.hash(rawSource);
}
@Override
public String toString() {
if (rawSource == null)
return "<any>";
if (rawSource instanceof Predicate)
return "matching predicate";
return rawSource.toString();
}
}
@@ -307,18 +307,4 @@ class Utils {
}
return regexFlags;
}
static int fromJsRegexFlags(String regexFlags) {
int flags = 0;
if (regexFlags.contains("i")) {
flags |= Pattern.CASE_INSENSITIVE;
}
if (regexFlags.contains("s")) {
flags |= Pattern.DOTALL;
}
if (regexFlags.contains("m")) {
flags |= Pattern.MULTILINE;
}
return flags;
}
}
@@ -72,9 +72,6 @@ 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) {
@@ -18,52 +18,38 @@ package com.microsoft.playwright.impl;
import com.google.gson.JsonObject;
import java.util.function.Function;
import java.util.function.Supplier;
import static com.microsoft.playwright.impl.Utils.createGuid;
public class WaitForEventLogger<T> implements Supplier<T>, Logger {
private final Function<Logger, T> supplier;
public class WaitForEventLogger<T> implements Supplier<T> {
private final Supplier<T> supplier;
private final ChannelOwner channel;
private final String waitId;
private final String apiName;
WaitForEventLogger(ChannelOwner channelOwner, String apiName, Function<Logger, T> supplier) {
WaitForEventLogger(ChannelOwner channelOwner, String apiName, Supplier<T> supplier) {
this.supplier = supplier;
this.channel = channelOwner;
this.apiName = apiName;
this.waitId = createGuid();
JsonObject info = new JsonObject();
info.addProperty("phase", "before");
sendWaitForEventInfo(info);
}
@Override
public T get() {
return channel.withLogging(apiName, () -> {
{
JsonObject info = new JsonObject();
info.addProperty("phase", "before");
sendWaitForEventInfo(info);
}
JsonObject info = new JsonObject();
info.addProperty("phase", "after");
try {
return supplier.apply(this);
} catch (RuntimeException e) {
info.addProperty("error", e.getMessage());
throw e;
} finally {
sendWaitForEventInfo(info);
}
});
}
@Override
public void log(String message) {
LoggingSupport.logApiIfEnabled(message);
JsonObject info = new JsonObject();
info.addProperty("phase", "log");
info.addProperty("message", message);
sendWaitForEventInfo(info);
info.addProperty("phase", "after");
try {
return supplier.get();
} catch (RuntimeException e) {
info.addProperty("error", e.getMessage());
throw e;
} finally {
sendWaitForEventInfo(info);
}
}
private void sendWaitForEventInfo(JsonObject info) {
@@ -71,6 +57,6 @@ public class WaitForEventLogger<T> implements Supplier<T>, Logger {
info.addProperty("waitId", waitId);
JsonObject params = new JsonObject();
params.add("info", info);
channel.sendMessageAsync("waitForEventInfo", params);
channel.withLogging(apiName, () -> channel.sendMessageAsync("waitForEventInfo", params));
}
}
@@ -87,7 +87,7 @@ class WebSocketImpl extends ChannelOwner implements WebSocket {
@Override
public WebSocketFrame waitForFrameReceived(WaitForFrameReceivedOptions options, Runnable code) {
return withWaitLogging("WebSocket.waitForFrameReceived", logger -> waitForFrameReceivedImpl(options, code));
return withWaitLogging("WebSocket.waitForFrameReceived", () -> waitForFrameReceivedImpl(options, code));
}
private WebSocketFrame waitForFrameReceivedImpl(WaitForFrameReceivedOptions options, Runnable code) {
@@ -99,7 +99,7 @@ class WebSocketImpl extends ChannelOwner implements WebSocket {
@Override
public WebSocketFrame waitForFrameSent(WaitForFrameSentOptions options, Runnable code) {
return withWaitLogging("WebSocket.waitForFrameSent", logger -> waitForFrameSentImpl(options, code));
return withWaitLogging("WebSocket.waitForFrameSent", () -> waitForFrameSentImpl(options, code));
}
private WebSocketFrame waitForFrameSentImpl(WaitForFrameSentOptions options, Runnable code) {
@@ -59,7 +59,7 @@ class WorkerImpl extends ChannelOwner implements Worker {
@Override
public Worker waitForClose(WaitForCloseOptions options, Runnable code) {
return withWaitLogging("Worker.waitForClose", logger -> waitForCloseImpl(options, code));
return withWaitLogging("Worker.waitForClose", () -> waitForCloseImpl(options, code));
}
private Worker waitForCloseImpl(WaitForCloseOptions options, Runnable code) {
@@ -19,8 +19,7 @@ package com.microsoft.playwright.options;
import com.microsoft.playwright.impl.RequestOptionsImpl;
/**
* The {@code RequestOptions} allows to create form data to be sent via {@code APIRequestContext}. Playwright will automatically
* determine content type of the request.
* The {@code RequestOptions} allows to create form data to be sent via {@code APIRequestContext}.
* <pre>{@code
* context.request().post(
* "https://example.com/submit",
@@ -28,33 +27,6 @@ import com.microsoft.playwright.impl.RequestOptionsImpl;
* .setQueryParam("page", 1)
* .setData("My data"));
* }</pre>
*
* <p> **Uploading html form data**
*
* <p> {@code FormData} class can be used to send a form to the server, by default the request will use
* {@code application/x-www-form-urlencoded} encoding:
* <pre>{@code
* context.request().post("https://example.com/signup", RequestOptions.create().setForm(
* FormData.create()
* .set("firstName", "John")
* .set("lastName", "Doe")));
* }</pre>
*
* <p> You can also send files as fields of an html form. The data will be encoded using <a
* href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST">{@code multipart/form-data}</a>:
* <pre>{@code
* Path path = Paths.get("members.csv");
* APIResponse response = context.request().post("https://example.com/upload_members",
* RequestOptions.create().setMultipart(FormData.create().set("membersList", path)));
* }</pre>
*
* <p> Alternatively, you can build the file payload manually:
* <pre>{@code
* FilePayload filePayload = new FilePayload("members.csv", "text/csv",
* "Alice, 33\nJohn, 35\n".getBytes(StandardCharsets.UTF_8));
* APIResponse response = context.request().post("https://example.com/upload_members",
* RequestOptions.create().setMultipart(FormData.create().set("membersList", filePayload)));
* }</pre>
*/
public interface RequestOptions {
/**
@@ -115,13 +87,6 @@ public interface RequestOptions {
* @param ignoreHTTPSErrors Whether to ignore HTTPS errors when sending network requests.
*/
RequestOptions setIgnoreHTTPSErrors(boolean ignoreHTTPSErrors);
/**
*
*
* @param maxRedirects Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is
* exceeded. Defaults to {@code 20}. Pass {@code 0} to not follow redirects.
*/
RequestOptions setMaxRedirects(int maxRedirects);
/**
* Changes the request method (e.g. <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT">PUT</a> or <a
* href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST">POST</a>).
@@ -195,7 +195,6 @@ 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,11 +19,8 @@ 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.*;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class TestAPIResponseAssertions extends TestBase {
@Test
@@ -41,62 +38,14 @@ public class TestAPIResponseAssertions extends TestBase {
@Test
void fail() {
APIResponse res = page.request().get(server.PREFIX + "/unknown");
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);
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());
}
assertTrue(didThrow);
}
}
@@ -18,8 +18,6 @@ package com.microsoft.playwright;
import org.junit.jupiter.api.*;
import com.microsoft.playwright.options.SameSiteAttribute;
import java.io.IOException;
import static com.microsoft.playwright.Utils.getBrowserNameFromEnv;
@@ -37,11 +35,9 @@ public class TestBase {
static final boolean isMac = Utils.getOS() == Utils.OS.MAC;
static final boolean isWindows = Utils.getOS() == Utils.OS.WINDOWS;
static final boolean headful;
static final SameSiteAttribute defaultSameSiteCookieValue;
static {
String headfulEnv = System.getenv("HEADFUL");
headful = headfulEnv != null && !"0".equals(headfulEnv) && !"false".equals(headfulEnv);
defaultSameSiteCookieValue = initSameSiteAttribute();
}
// Fields reset before each test.
@@ -76,12 +72,8 @@ public class TestBase {
return options;
}
Playwright.CreateOptions playwrightOptions() {
return null;
}
void initBrowserType() {
playwright = Playwright.create(playwrightOptions());
playwright = Playwright.create();
browserType = Utils.getBrowserTypeFromEnv(playwright);
}
@@ -149,11 +141,4 @@ public class TestBase {
page = null;
}
}
private static SameSiteAttribute initSameSiteAttribute() {
if (isChromium()) return SameSiteAttribute.LAX;
if (isWebKit()) return SameSiteAttribute.NONE;
// for firefox version >= 103 'None' is used.
return SameSiteAttribute.NONE;
}
}
@@ -48,8 +48,12 @@ public class TestBrowser extends TestBase {
@Test
void shouldThrowUponSecondCreateNewPage() {
Page page = browser.newPage();
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.context().newPage());
assertTrue(e.getMessage().contains("Please use browser.newContext()"));
try {
page.context().newPage();
fail("newPage should throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Please use browser.newContext()"));
}
page.close();
}
@@ -16,6 +16,7 @@
package com.microsoft.playwright;
import com.google.gson.Gson;
import com.microsoft.playwright.options.Cookie;
import org.junit.jupiter.api.Test;
@@ -26,6 +27,7 @@ import java.util.concurrent.Future;
import static com.microsoft.playwright.Utils.assertJsonEquals;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.junit.jupiter.api.Assertions.*;
@@ -49,11 +51,15 @@ public class TestBrowserContextAddCookies extends TestBase {
"}");
assertEquals("username=John Doe", documentCookie);
List<Cookie> cookies = context.cookies();
assertEquals(1, cookies.size());
context.clearCookies();
assertEquals(0, context.cookies().size());
context.addCookies(cookies);
assertJsonEquals(cookies, context.cookies());
assertEquals(emptyList(), context.cookies());
context.addCookies(asList(new Cookie(cookies.get(0).name, cookies.get(0).value)
.setDomain(cookies.get(0).domain)
.setPath(cookies.get(0).path)
.setExpires(cookies.get(0).expires)
.setSameSite(cookies.get(0).sameSite)
));
assertJsonEquals(new Gson().toJson(cookies), context.cookies());
}
@Test
@@ -242,19 +248,27 @@ public class TestBrowserContextAddCookies extends TestBase {
@Test
void shouldNotSetACookieWithBlankPageURL() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> context.addCookies(asList(
new Cookie("example-cookie", "best").setUrl(server.EMPTY_PAGE),
new Cookie("example-cookie-blank", "best").setUrl("about:blank")
)));
assertTrue(e.getMessage().contains("Blank page can not have cookie \"example-cookie-blank\""));
try {
context.addCookies(asList(
new Cookie("example-cookie", "best").setUrl(server.EMPTY_PAGE),
new Cookie("example-cookie-blank", "best").setUrl("about:blank")
));
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Blank page can not have cookie \"example-cookie-blank\""));
}
}
@Test
void shouldNotSetACookieOnADataURLPage() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> context.addCookies(asList(
new Cookie("example-cookie", "best").setUrl("data:,Hello%2C%20World!")
)));
assertTrue(e.getMessage().contains("Data URL page can not have cookie \"example-cookie\""));
try {
context.addCookies(asList(
new Cookie("example-cookie", "best").setUrl("data:,Hello%2C%20World!")
));
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Data URL page can not have cookie \"example-cookie\""));
}
}
@Test
@@ -116,18 +116,22 @@ public class TestBrowserContextBasic extends TestBase {
@Test
void shouldNotAllowDeviceScaleFactorWithNullViewport() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
browser.newContext(new Browser.NewContextOptions().setDeviceScaleFactor(1.0).setViewportSize(null));
});
assertTrue(e.getMessage().contains("\"deviceScaleFactor\" option is not supported with null \"viewport\""));
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("\"deviceScaleFactor\" option is not supported with null \"viewport\""));
}
}
@Test
void shouldNotAllowIsMobileWithNullViewport() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
browser.newContext(new Browser.NewContextOptions().setIsMobile(true).setViewportSize(null));
});
assertTrue(e.getMessage().contains("\"isMobile\" option is not supported with null \"viewport\""));
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("\"isMobile\" option is not supported with null \"viewport\""));
}
}
@Test
@@ -139,10 +143,12 @@ public class TestBrowserContextBasic extends TestBase {
@Test
void closeShouldAbortFutureEvent() {
BrowserContext context = browser.newContext();
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
context.waitForPage(() -> context.close());
});
assertTrue(e.getMessage().contains("Context closed"));
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Context closed"));
}
}
@Test
@@ -205,11 +211,15 @@ public class TestBrowserContextBasic extends TestBase {
BrowserContext context = browser.newContext(new Browser.NewContextOptions().setJavaScriptEnabled(false));
Page page = context.newPage();
page.navigate("data:text/html, <script>var something = 'forbidden'</script>");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.evaluate("something"));
if (isWebKit())
assertTrue(e.getMessage().contains("Can\'t find variable: something"));
else
assertTrue(e.getMessage().contains("something is not defined"));
try {
page.evaluate("something");
fail("did not throw");
} catch (PlaywrightException e) {
if (isWebKit())
assertTrue(e.getMessage().contains("Can\'t find variable: something"));
else
assertTrue(e.getMessage().contains("something is not defined"));
}
context.close();
}
@@ -234,7 +244,11 @@ public class TestBrowserContextBasic extends TestBase {
void shouldWorkWithOfflineOption() {
BrowserContext context = browser.newContext(new Browser.NewContextOptions().setOffline(true));
Page page = context.newPage();
assertThrows(PlaywrightException.class, () -> page.navigate(server.EMPTY_PAGE));
try {
page.navigate(server.EMPTY_PAGE);
fail("did not throw");
} catch (PlaywrightException e) {
}
context.setOffline(false);
Response response = page.navigate(server.EMPTY_PAGE);
@@ -20,6 +20,7 @@ import com.microsoft.playwright.options.Cookie;
import com.microsoft.playwright.options.SameSiteAttribute;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledIf;
import org.junit.jupiter.api.condition.EnabledIf;
import java.util.Comparator;
import java.util.List;
@@ -28,7 +29,8 @@ import java.util.stream.Collectors;
import static com.microsoft.playwright.Utils.assertJsonEquals;
import static com.microsoft.playwright.Utils.getOS;
import static java.util.Arrays.asList;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class TestBrowserContextCookies extends TestBase {
@Test
@@ -58,28 +60,31 @@ public class TestBrowserContextCookies extends TestBase {
page.navigate(server.EMPTY_PAGE);
// @see https://en.wikipedia.org/wiki/Year_2038_problem
Object documentCookie = page.evaluate("() => {\n" +
" const date = new Date('1/1/2038');\n" +
" document.cookie = `username=John Doe;expires=${date.toUTCString()}`;\n" +
" return document.cookie;\n" +
"}");
" const date= new Date('1/1/2038');\n" +
" document.cookie = `username=John Doe;expires=${date.toUTCString()}`;\n" +
" return document.cookie;\n" +
" }");
assertEquals("username=John Doe", documentCookie);
List<Cookie> cookies = context.cookies();
assertEquals(1, cookies.size());
assertEquals("username", cookies.get(0).name);
assertEquals("John Doe", cookies.get(0).value);
assertEquals("localhost", cookies.get(0).domain);
assertEquals("/", cookies.get(0).path);
assertFalse(cookies.get(0).httpOnly);
assertFalse(cookies.get(0).secure);
assertEquals(defaultSameSiteCookieValue, cookies.get(0).sameSite);
Cookie cookie = context.cookies().get(0);
assertEquals("username", cookie.name);
assertEquals("John Doe", cookie.value);
assertEquals("localhost", cookie.domain);
assertEquals("/", cookie.path);
// Browsers start to cap cookies with 400 days max expires value.
// See https://github.com/httpwg/http-extensions/pull/1732
// Chromium patch: https://chromium.googlesource.com/chromium/src/+/aaa5d2b55478eac2ee642653dcd77a50ac3faff6
// We want to make sure that expires date is at least 400 days in future.
int FOUR_HUNDRED_DAYS = 1000 * 60 * 60 * 24 * 400;
int FIVE_MINUTES = 1000 * 60 * 5; // relax condition a bit to make sure test is not flaky.
assertTrue(cookies.get(0).expires > ((System.currentTimeMillis() + FOUR_HUNDRED_DAYS - FIVE_MINUTES) / 1000));
Double timestamp = (Double) page.evaluate("const FOUR_HUNDRED_DAYS = 1000 * 60 * 60 * 24 * 400;\n" +
" const FIVE_MINUTES = 1000 * 60 * 5; // relax condition a bit to make sure test is not flaky.\n" +
" (Date.now() + FOUR_HUNDRED_DAYS - FIVE_MINUTES) / 1000;");
assertTrue(cookie.expires > timestamp, cookie.expires + " > " + timestamp + " failed.");
assertEquals(false, cookie.httpOnly);
assertEquals(false, cookie.secure);
if (isChromium()) {
assertEquals(SameSiteAttribute.LAX, cookie.sameSite);
} else {
assertEquals(SameSiteAttribute.NONE, cookie.sameSite);
}
}
@Test
@@ -58,16 +58,28 @@ public class TestBrowserContextExposeFunction extends TestBase {
void shouldThrowForDuplicateRegistrations() {
context.exposeFunction("foo", args -> null);
context.exposeFunction("bar", args -> null);
PlaywrightException e = assertThrows(PlaywrightException.class, () -> context.exposeFunction("foo", args -> null));
assertTrue(e.getMessage().contains("Function \"foo\" has been already registered"));
try {
context.exposeFunction("foo", args -> null);
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Function \"foo\" has been already registered"));
}
Page page = context.newPage();
e = assertThrows(PlaywrightException.class, () -> page.exposeFunction("foo", args -> null));
assertTrue(e.getMessage().contains("Function \"foo\" has been already registered in the browser context"));
try {
page.exposeFunction("foo", args -> null);
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Function \"foo\" has been already registered in the browser context"));
}
page.exposeFunction("baz", args -> null);
e = assertThrows(PlaywrightException.class, () -> context.exposeFunction("baz", args -> null));
assertTrue(e.getMessage().contains("Function \"baz\" has been already registered in one of the pages"));
try {
context.exposeFunction("baz", args -> null);
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Function \"baz\" has been already registered in one of the pages"));
}
}
@Test
@@ -51,16 +51,24 @@ public class TestBrowserContextFetch extends TestBase {
@Test
void shouldThrowOnNetworkError() {
server.setRoute("/test", exchange -> exchange.getResponseBody().close());
PlaywrightException e = assertThrows(PlaywrightException.class, () -> context.request().get(server.PREFIX + "/test"));
assertTrue(e.getMessage().contains("socket hang up"), e.getMessage());
try {
context.request().get(server.PREFIX + "/test");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("socket hang up"), e.getMessage());
}
}
@Test
void shouldThrowOnNetworkErrorAfterRedirect() {
server.setRedirect("/redirect", "/test");
server.setRoute("/test", exchange -> exchange.getResponseBody().close());
PlaywrightException e = assertThrows(PlaywrightException.class, () -> context.request().get(server.PREFIX + "/redirect"));
assertTrue(e.getMessage().contains("socket hang up"), e.getMessage());
try {
context.request().get(server.PREFIX + "/redirect");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("socket hang up"), e.getMessage());
}
}
@Test
@@ -72,8 +80,12 @@ public class TestBrowserContextFetch extends TestBase {
writer.write("<title>A");
}
});
PlaywrightException e = assertThrows(PlaywrightException.class, () -> context.request().get(server.PREFIX + "/test"));
assertTrue(e.getMessage().contains("aborted"), e.getMessage());
try {
context.request().get(server.PREFIX + "/test");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("aborted"), e.getMessage());
}
}
@Test
@@ -86,8 +98,12 @@ public class TestBrowserContextFetch extends TestBase {
writer.write("<title>A");
}
});
PlaywrightException e = assertThrows(PlaywrightException.class, () -> context.request().get(server.PREFIX + "/redirect"));
assertTrue(e.getMessage().contains("aborted"), e.getMessage());
try {
context.request().get(server.PREFIX + "/redirect");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("aborted"), e.getMessage());
}
}
@Test
@@ -118,10 +134,12 @@ public class TestBrowserContextFetch extends TestBase {
@Test
void getShouldSupportFailOnStatusCode() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
context.request().get(server.PREFIX + "/does-not-exist.html", RequestOptions.create().setFailOnStatusCode(true));
});
assertTrue(e.getMessage().contains("404 Not Found"), e.getMessage());
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("404 Not Found"), e.getMessage());
}
}
@Test
@@ -367,20 +385,29 @@ public class TestBrowserContextFetch extends TestBase {
@Test
void shouldThrowOnInvalidHeaderValue() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
context.request().get(server.EMPTY_PAGE, RequestOptions.create()
.setHeader("foo", "недопустимое значение"));
});
assertTrue(e.getMessage().contains("Invalid character in header content"), e.getMessage());
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Invalid character in header content"), e.getMessage());
}
}
@Test
void shouldThrowOnNonHttpSProtocol() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> context.request().get("data:text/plain,test"));
assertTrue(e.getMessage().contains("Protocol \"data:\" not supported"), e.getMessage());
e = assertThrows(PlaywrightException.class, () -> context.request().get("file:///tmp/foo"));
assertTrue(e.getMessage().contains("Protocol \"file:\" not supported"), e.getMessage());
try {
context.request().get("data:text/plain,test");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Protocol \"data:\" not supported"), e.getMessage());
}
try {
context.request().get("file:///tmp/foo");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Protocol \"file:\" not supported"), e.getMessage());
}
}
@Test
@@ -390,10 +417,12 @@ public class TestBrowserContextFetch extends TestBase {
exchange.sendResponseHeaders(200, 4096);
});
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
context.request().get(server.PREFIX + "/slow", RequestOptions.create().setTimeout(100));
});
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
}
}
@Test
@@ -424,8 +453,12 @@ public class TestBrowserContextFetch extends TestBase {
});
context.setDefaultTimeout(100);
PlaywrightException e = assertThrows(PlaywrightException.class, () -> context.request().get(server.PREFIX + "/redirect"));
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
try {
context.request().get(server.PREFIX + "/redirect");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
}
}
@Test
@@ -433,8 +466,12 @@ public class TestBrowserContextFetch extends TestBase {
APIResponse response = context.request().get(server.PREFIX + "/simple.json");
assertEquals("{\"foo\": \"bar\"}\n", response.text());
response.dispose();
PlaywrightException e = assertThrows(PlaywrightException.class, () -> response.body());
assertTrue(e.getMessage().contains("Response has been disposed"), e.getMessage());
try {
response.body();
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Response has been disposed"), e.getMessage());
}
}
@Test
@@ -442,9 +479,13 @@ public class TestBrowserContextFetch extends TestBase {
APIResponse response = context.request().get(server.PREFIX + "/simple.json");
assertEquals("{\"foo\": \"bar\"}\n", response.text());
context.close();
PlaywrightException e = assertThrows(PlaywrightException.class, () -> response.body());
assertTrue(e.getMessage().contains("Response has been disposed") ||
try {
response.body();
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Response has been disposed") ||
e.getMessage().contains("Target page, context or browser has been closed"), e.getMessage());
}
}
@Test
void shouldOverrideRequestParameters() throws ExecutionException, InterruptedException {
@@ -573,11 +614,17 @@ public class TestBrowserContextFetch extends TestBase {
}
@Test
void shouldNotThrowWhenDataPassedForUnsupportedRequest() {
context.request().fetch(server.EMPTY_PAGE, RequestOptions.create()
.setMethod("GET").setData("bar"));
void shouldThrowWhenDataPassedForUnsupportedRequest() {
try {
context.request().fetch(server.EMPTY_PAGE, RequestOptions.create()
.setMethod("GET").setData("bar"));
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Method GET does not accept post data"), e.getMessage());
}
}
@Test
void contextRequestShouldExportSameStorageStateAsContext() {
server.setRoute("/setcookie.html", exchange -> {
@@ -619,10 +666,18 @@ public class TestBrowserContextFetch extends TestBase {
return null;
});
page.evaluate("() => setTimeout(closeContext, 1000);");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> context.request().get(server.EMPTY_PAGE));
assertTrue(e.getMessage().contains("Request context disposed"), e.getMessage());
try {
context.request().get(server.EMPTY_PAGE);
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Request context disposed"), e.getMessage());
}
e = assertThrows(PlaywrightException.class, () -> context.request().post(server.EMPTY_PAGE));
assertTrue(e.getMessage().contains("Target page, context or browser has been closed"), e.getMessage());
try {
context.request().post(server.EMPTY_PAGE);
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Target page, context or browser has been closed"), e.getMessage());
}
}
}
@@ -79,7 +79,11 @@ public class TestBrowserContextHar extends TestBase {
Path path = Paths.get("src/test/resources/har-fulfill.har");
context.routeFromHAR(path);
Page page = context.newPage();
assertThrows(PlaywrightException.class, () -> page.navigate(server.EMPTY_PAGE));
try {
page.navigate(server.EMPTY_PAGE);
fail("did not throw");
} catch (PlaywrightException e) {
}
}
@Test
@@ -346,7 +350,12 @@ public class TestBrowserContextHar extends TestBase {
assertEquals("2", page2.evaluate(fetchFunction, "2"));
assertEquals("3", page2.evaluate(fetchFunction, "3"));
assertEquals("3", page2.evaluate(fetchFunction, "3"));
assertThrows(PlaywrightException.class, () -> page2.evaluate(fetchFunction, "4"));
try {
Object result = page2.evaluate(fetchFunction, "4");
System.out.println(result);
fail("did not throw");
} catch (PlaywrightException e) {
}
}
}
@@ -47,9 +47,9 @@ public class TestBrowserContextProxy extends TestBase {
@EnabledIf(value="isChromiumWindows", disabledReason="Platform-specific")
void shouldThrowForMissingGlobalProxyOnChromiumWindows() {
try (Browser browser = browserType.launch(createLaunchOptions())) {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
browser.newContext(new Browser.NewContextOptions().setProxy("localhost:" + server.PORT));
});
browser.newContext(new Browser.NewContextOptions().setProxy("localhost:" + server.PORT));
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Browser needs to be launched with the global proxy"));
}
}
@@ -179,9 +179,23 @@ public class TestBrowserContextProxy extends TestBase {
page.navigate("http://0.non.existent.domain.for.the.test/target.html");
assertEquals("Served by the proxy", page.title());
assertThrows(PlaywrightException.class, () -> page.navigate("http://1.non.existent.domain.for.the.test/target.html"));
assertThrows(PlaywrightException.class, () -> page.navigate("http://2.non.existent.domain.for.the.test/target.html"));
assertThrows(PlaywrightException.class, () -> page.navigate("http://foo.is.the.another.test/target.html"));
try {
page.navigate("http://1.non.existent.domain.for.the.test/target.html");
fail("did not throw");
} catch (PlaywrightException exception) {
}
try {
page.navigate("http://2.non.existent.domain.for.the.test/target.html");
fail("did not throw");
} catch (PlaywrightException e) {
}
try {
page.navigate("http://foo.is.the.another.test/target.html");
fail("did not throw");
} catch (PlaywrightException e) {
}
page.navigate("http://3.non.existent.domain.for.the.test/target.html");
assertEquals("Served by the proxy", page.title());
@@ -169,8 +169,12 @@ public class TestBrowserContextRoute extends TestBase {
throw new RuntimeException("My Exception");
});
RuntimeException e = assertThrows(RuntimeException.class, () -> page.navigate(server.EMPTY_PAGE));
assertTrue(e.getMessage().contains("My Exception"), e.getMessage());
try {
page.navigate(server.EMPTY_PAGE);
fail("did not throw");
} catch (RuntimeException e) {
assertTrue(e.getMessage().contains("My Exception"), e.getMessage());
}
}
@Test
@@ -183,8 +187,12 @@ public class TestBrowserContextRoute extends TestBase {
// Fulfilling with dsiposed response will lead to a server-side exception.
route.fulfill(new Route.FulfillOptions().setResponse(response));
});
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.navigate(server.EMPTY_PAGE));
assertTrue(e.getMessage().contains("Fetch response has been disposed"), e.getMessage());
try {
page.navigate(server.EMPTY_PAGE);
fail("did not throw");
} catch (RuntimeException e) {
assertTrue(e.getMessage().contains("Fetch response has been disposed"), e.getMessage());
}
}
@Test
@@ -193,8 +201,12 @@ public class TestBrowserContextRoute extends TestBase {
page.route("**/*", route -> {
route.resume(new Route.ResumeOptions().setUrl("file:///tmp"));
});
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.navigate(server.EMPTY_PAGE));
assertTrue(e.getMessage().contains("New URL must have same protocol as overridden URL"), e.getMessage());
try {
page.navigate(server.EMPTY_PAGE);
fail("did not throw");
} catch (RuntimeException e) {
assertTrue(e.getMessage().contains("New URL must have same protocol as overridden URL"), e.getMessage());
}
}
@@ -248,7 +260,12 @@ public class TestBrowserContextRoute extends TestBase {
route.fallback();
});
assertThrows(PlaywrightException.class, () -> page.navigate(server.EMPTY_PAGE));
try {
page.navigate(server.EMPTY_PAGE);
fail("did not throw");
} catch (PlaywrightException e) {
assertNotNull(e);
}
assertFalse(failed[0]);
}
@@ -38,8 +38,12 @@ public class TestBrowserContextStrict extends TestBase {
@Test
void shouldFailPageTextContentInStrictMode() {
page.setContent("<span>span1</span><div><span>target</span></div>");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.textContent("span"));
assertTrue(e.getMessage().contains("strict mode violation"));
try {
page.textContent("span");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("strict mode violation"));
}
}
@Test
@@ -43,7 +43,11 @@ public class TestBrowserTypeBasic extends TestBase {
@Test
@DisabledIf(value="com.microsoft.playwright.TestBase#isChromium", disabledReason="Non-chromium behavior")
void shouldThrowWhenTryingToConnectWithNotChromium() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> browserType.connectOverCDP("foo"));
assertTrue(e.getMessage().contains("Connecting over CDP is only supported in Chromium."));
try {
browserType.connectOverCDP("foo");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Connecting over CDP is only supported in Chromium."));
}
}
}
@@ -16,7 +16,7 @@
package com.microsoft.playwright;
import com.microsoft.playwright.impl.driver.Driver;
import com.microsoft.playwright.impl.Driver;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeAll;
@@ -60,8 +60,8 @@ public class TestBrowserTypeConnect extends TestBase {
private static BrowserServer launchBrowserServer(BrowserType browserType) {
try {
Driver driver = Driver.ensureDriverInstalled(Collections.emptyMap(), false);
Path dir = driver.driverPath().getParent();
Path driver = Driver.ensureDriverInstalled(Collections.emptyMap(), false);
Path dir = driver.getParent();
String node = dir.resolve(isWindows ? "node.exe" : "node").toString();
String cliJs = dir.resolve("package/lib/cli/cli.js").toString();
// We launch node process directly instead of using playwright.sh script as killing the script
@@ -192,8 +192,12 @@ public class TestBrowserTypeConnect extends TestBase {
remote.kill();
assertEquals(1, disconnected1[0]);
// Tickle connection so that it gets a chance to dispatch disconnect event.
assertThrows(PlaywrightException.class, () -> page2.title());
try {
// Tickle connection so that it gets a chance to dispatch disconnect event.
page2.title();
fail("did not throw");
} catch (PlaywrightException e) {
}
assertEquals(1, disconnected2[0]);
}
@@ -234,8 +238,11 @@ public class TestBrowserTypeConnect extends TestBase {
}
}
assertFalse(remote.isConnected());
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.evaluate("1 + 1"));
assertTrue(e.getMessage().contains("Browser has been closed"), e.getMessage());
try {
page.evaluate("1 + 1");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Browser has been closed"), e.getMessage());
}
assertFalse(remote.isConnected());
}
@@ -255,8 +262,12 @@ public class TestBrowserTypeConnect extends TestBase {
}
}
assertFalse(browser.isConnected());
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.waitForNavigation(() -> {}));
assertTrue(e.getMessage().contains("Page closed") || e.getMessage().contains("Browser has been closed"), e.getMessage());
try {
page.waitForNavigation(() -> {});
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Page closed") || e.getMessage().contains("Browser has been closed"), e.getMessage());
}
}
@Test
@@ -266,10 +277,12 @@ public class TestBrowserTypeConnect extends TestBase {
server.setRoute("/one-style.css", r -> {});
page.onRequest(r -> remote.close());
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
page.navigate(server.PREFIX + "/one-style.html", new Page.NavigateOptions().setTimeout(60000));
});
assertTrue(e.getMessage().contains("Browser has been closed"));
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Browser has been closed"));
}
}
@Test
@@ -395,8 +408,12 @@ public class TestBrowserTypeConnect extends TestBase {
Path savedAsPath = tempDir.resolve("my-video.webm");
page.video().saveAs(savedAsPath);
assertTrue(Files.exists(savedAsPath));
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.video().path());
assertTrue(e.getMessage().contains("Path is not available when using browserType.connect(). Use saveAs() to save a local copy."));
try {
page.video().path();
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Path is not available when using browserType.connect(). Use saveAs() to save a local copy."));
}
}
@@ -418,8 +435,12 @@ public class TestBrowserTypeConnect extends TestBase {
download.saveAs(nestedPath);
assertTrue(Files.exists(nestedPath));
assertEquals("Hello world", new String(Files.readAllBytes(nestedPath), StandardCharsets.UTF_8));
PlaywrightException e = assertThrows(PlaywrightException.class, () -> download.path());
assertTrue(e.getMessage().contains("Path is not available when using browserType.connect(). Use download.saveAs() to save a local copy."));
try {
download.path();
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Path is not available when using browserType.connect(). Use download.saveAs() to save a local copy."));
}
page.close();
}
@@ -438,8 +459,12 @@ public class TestBrowserTypeConnect extends TestBase {
Download download = page.waitForDownload(() -> page.click("a"));
Path userPath = tempDir.resolve("download.txt");
download.delete();
PlaywrightException e = assertThrows(PlaywrightException.class, () -> download.saveAs(userPath));
assertTrue(e.getMessage().contains("Target page, context or browser has been closed"));
try {
download.saveAs(userPath);
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Target page, context or browser has been closed"));
}
page.close();
}
@@ -80,10 +80,12 @@ public class TestChromiumTracing extends TestBase {
browser.startTracing(page, new Browser.StartTracingOptions()
.setPath(outputTraceFile));
Page newPage = browser.newPage();
assertThrows(PlaywrightException.class, () -> {
try {
browser.startTracing(newPage, new Browser.StartTracingOptions()
.setPath(outputTraceFile));
});
fail("did not throw");
} catch (PlaywrightException e) {
}
newPage.close();
browser.stopTracing();
}
@@ -172,10 +172,14 @@ public class TestClick extends TestBase {
void shouldNotWaitWithForce() {
page.navigate(server.PREFIX + "/input/button.html");
page.evalOnSelector("button", "b => b.style.display = 'none'");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
Exception exception = null;
try {
page.click("button", new Page.ClickOptions().setForce(true));
});
assertTrue(e.getMessage().contains("Element is not visible"));
} catch (PlaywrightException e) {
exception = e;
}
assertNotNull(exception);
assertTrue(exception.getMessage().contains("Element is not visible"));
assertEquals("Was not clicked", page.evaluate("result"));
}
@@ -424,8 +428,8 @@ public class TestClick extends TestBase {
int expectedY = 18;
if (isWebKit()) {
// WebKit rounds up during css -> dip -> css conversion.
expectedX = 26;
expectedY = 17;
expectedX = 29;
expectedY = 19;
} else if (isChromium() && !headful) {
// Headless Chromium rounds down during css -> dip -> css conversion.
expectedX = 27;
@@ -560,10 +564,12 @@ public class TestClick extends TestBase {
page.evaluate("addButton()");
ElementHandle handle = page.querySelector("button");
page.evaluate("stopButton(true)");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
handle.click(new ElementHandle.ClickOptions().setForce(true));
});
assertTrue(e.getMessage().contains("Element is not attached to the DOM"));
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Element is not attached to the DOM"));
}
assertEquals(null, page.evaluate("window.clicked"));
}
@@ -192,10 +192,12 @@ public class TestDefaultBrowserContext2 extends TestBase {
BrowserType.LaunchPersistentContextOptions options = new BrowserType.LaunchPersistentContextOptions()
.setArgs(asList(server.EMPTY_PAGE));
Path userDataDir = Files.createTempDirectory("user-data-dir-");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
browserType.launchPersistentContext(userDataDir, options);
});
assertTrue(e.getMessage().contains("can not specify page"));
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("can not specify page"));
}
}
@Test
@@ -102,8 +102,9 @@ public class TestDownload extends TestBase {
assertTrue(error[0].getMessage().contains("Download is starting"));
assertEquals("about:blank", page.url());
} else {
assertNotNull(error[0]);
assertTrue(error[0].getMessage().contains("Download is starting"));
assertNotNull(response[0]);
assertEquals(200, response[0].status());
assertEquals(server.PREFIX + "/download", page.url());
}
page.close();
}
@@ -115,9 +116,13 @@ public class TestDownload extends TestBase {
Download download = page.waitForDownload(() -> page.click("a"));
assertEquals(server.PREFIX + "/downloadWithFilename", download.url());
assertEquals("file.txt", download.suggestedFilename());
PlaywrightException e = assertThrows(PlaywrightException.class, () -> download.path());
assertTrue(download.failure().contains("acceptDownloads"));
assertTrue(e.getMessage().contains("acceptDownloads: true"));
try {
download.path();
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(download.failure().contains("acceptDownloads"));
assertTrue(e.getMessage().contains("acceptDownloads: true"));
}
}
}
@Test
@@ -238,8 +243,12 @@ public class TestDownload extends TestBase {
Download download = page.waitForDownload(() -> page.click("a"));
Path userPath = Files.createTempFile("download-", ".txt");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> download.saveAs(userPath));
assertTrue(e.getMessage().contains("Pass { acceptDownloads: true } when you are creating your browser context"));
try {
download.saveAs(userPath);
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Pass { acceptDownloads: true } when you are creating your browser context"));
}
page.close();
}
@@ -251,8 +260,12 @@ public class TestDownload extends TestBase {
Path userPath = Files.createTempFile("download-", ".txt");
download.delete();
PlaywrightException e = assertThrows(PlaywrightException.class, () -> download.saveAs(userPath));
assertTrue(e.getMessage().contains("Target page, context or browser has been closed"), e.getMessage());
try {
download.saveAs(userPath);
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Target page, context or browser has been closed"), e.getMessage());
}
page.close();
}
@@ -60,8 +60,12 @@ public class TestElementHandleClick extends TestBase {
page.navigate(server.PREFIX + "/input/button.html");
ElementHandle button = page.querySelector("button");
page.evaluate("button => button.remove()", button);
PlaywrightException e = assertThrows(PlaywrightException.class, () -> button.click());
assertTrue(e.getMessage().contains("Element is not attached to the DOM"));
try {
button.click();
fail("click should throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Element is not attached to the DOM"));
}
}
@Test
@@ -69,10 +73,12 @@ public class TestElementHandleClick extends TestBase {
page.navigate(server.PREFIX + "/input/button.html");
ElementHandle button = page.querySelector("button");
page.evaluate("button => button.style.display = 'none'", button);
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
button.click(new ElementHandle.ClickOptions().setForce(true));
});
assertTrue(e.getMessage().contains("Element is not visible"));
fail("click should throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Element is not visible"));
}
}
@Test
@@ -80,20 +86,24 @@ public class TestElementHandleClick extends TestBase {
page.navigate(server.PREFIX + "/input/button.html");
ElementHandle button = page.querySelector("button");
page.evaluate("button => button.parentElement.style.display = 'none'", button);
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
button.click(new ElementHandle.ClickOptions().setForce(true));
});
assertTrue(e.getMessage().contains("Element is not visible"));
fail("click should throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Element is not visible"));
}
}
@Test
void shouldThrowForBrElementsWithForce() {
page.setContent("hello<br>goodbye");
ElementHandle br = page.querySelector("br");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
br.click(new ElementHandle.ClickOptions().setForce(true));
});
assertTrue(e.getMessage().contains("Element is outside of the viewport"));
fail("click should throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Element is outside of the viewport"));
}
}
@Test
@@ -57,12 +57,19 @@ public class TestElementHandleConvenience extends TestBase {
ElementHandle handle = page.querySelector("#input");
assertEquals("input value", handle.inputValue());
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.inputValue("#inner"));
assertTrue(e.getMessage().contains("Node is not an <input>, <textarea> or <select> element"), e.getMessage());
try {
page.inputValue("#inner");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Node is not an <input>, <textarea> or <select> element"), e.getMessage());
}
ElementHandle handle2 = page.querySelector("#inner");
e = assertThrows(PlaywrightException.class, () -> handle2.inputValue());
assertTrue(e.getMessage().contains("Node is not an <input>, <textarea> or <select> element"), e.getMessage());
try {
handle2.inputValue();
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Node is not an <input>, <textarea> or <select> element"), e.getMessage());
}
}
@Test
@@ -84,11 +91,19 @@ public class TestElementHandleConvenience extends TestBase {
@Test
void innerTextShouldThrow() {
page.setContent("<svg>text</svg>");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.innerText("svg"));
assertTrue(e.getMessage().contains("Node is not an HTMLElement"), e.getMessage());
try {
page.innerText("svg");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Node is not an HTMLElement"), e.getMessage());
}
ElementHandle handle = page.querySelector("svg");
e = assertThrows(PlaywrightException.class, () -> handle.innerText());
assertTrue(e.getMessage().contains("Node is not an HTMLElement"), e.getMessage());
try {
handle.innerText();
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Node is not an HTMLElement"), e.getMessage());
}
}
@Test
@@ -252,7 +267,11 @@ public class TestElementHandleConvenience extends TestBase {
handle.evaluate("input => input.checked = false");
assertFalse(handle.isChecked());
assertFalse(page.isChecked("input"));
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.isChecked("div"));
assertTrue(e.getMessage().contains("Not a checkbox or radio button"));
try {
page.isChecked("div");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Not a checkbox or radio button"));
}
}
}
@@ -47,10 +47,12 @@ public class TestElementHandleSelectText extends TestBase {
page.navigate(server.PREFIX + "/input/textarea.html");
ElementHandle textarea = page.querySelector("textarea");
textarea.evaluate("e => e.style.display = 'none'");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
textarea.selectText(new ElementHandle.SelectTextOptions().setTimeout(3000));
});
assertTrue(e.getMessage().contains("element is not visible"));
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("element is not visible"));
}
}
// @Test
@@ -20,7 +20,8 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledIf;
import static com.microsoft.playwright.options.ElementState.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
public class TestElementHandleWaitForElementState extends TestBase {
@@ -50,10 +51,12 @@ public class TestElementHandleWaitForElementState extends TestBase {
void shouldTimeoutWaitingForVisible() {
page.setContent("<div style='display:none'>content</div>");
ElementHandle div = page.querySelector("div");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
div.waitForElementState(VISIBLE, new ElementHandle.WaitForElementStateOptions().setTimeout(1000));
});
assertTrue(e.getMessage().contains("Timeout 1000ms exceeded"));
fail("did not throw");
} catch (TimeoutError e) {
assertTrue(e.getMessage().contains("Timeout 1000ms exceeded"));
}
}
@Test
@@ -61,8 +64,12 @@ public class TestElementHandleWaitForElementState extends TestBase {
page.setContent("<div style='display:none'>content</div>");
ElementHandle div = page.querySelector("div");
div.evaluate("div => div.remove()");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> div.waitForElementState(VISIBLE));
assertTrue(e.getMessage().contains("Element is not attached to the DOM"));
try {
div.waitForElementState(VISIBLE);
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Element is not attached to the DOM"));
}
}
@Test
@@ -104,8 +111,12 @@ public class TestElementHandleWaitForElementState extends TestBase {
page.setContent("<button disabled>Target</button>");
ElementHandle button = page.querySelector("button");
button.evaluate("button => button.remove()");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> button.waitForElementState(ENABLED));
assertTrue(e.getMessage().contains("Element is not attached to the DOM"));
try {
button.waitForElementState(ENABLED);
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Element is not attached to the DOM"));
}
}
@Test
@@ -119,10 +119,12 @@ public class TestEvalOnSelector extends TestBase {
@Test
void shouldThrowErrorIfNoElementIsFound() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
page.evalOnSelector("section", "e => e.id");
});
assertTrue(e.getMessage().contains("failed to find element matching selector \"section\""));
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("failed to find element matching selector \"section\""));
}
}
@Test
@@ -164,20 +166,23 @@ public class TestEvalOnSelector extends TestBase {
@Test
void shouldThrowOnMultipleCaptures() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
page.evalOnSelector("*css=div >> *css=span", "e => e.outerHTML");
});
assertTrue(e.getMessage().contains("Only one of the selectors can capture using * modifier"));
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Only one of the selectors can capture using * modifier"));
}
}
@Test
void shouldThrowOnMalformedCapture() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
page.evalOnSelector("*=div", "e => e.outerHTML");
});
assertTrue(e.getMessage().contains("Unknown engine \"\" while parsing selector *=div"));
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Unknown engine \"\" while parsing selector *=div"));
}
}
@Test
void shouldWorkWithSpacesInCssAttributes() {
page.setContent("<div><input placeholder='Select date'></div>");
@@ -21,7 +21,8 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIf;
import static com.microsoft.playwright.Utils.mapOf;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
public class TestFirefoxLauncher extends TestBase {
@@ -46,7 +47,11 @@ public class TestFirefoxLauncher extends TestBase {
"network.proxy.http_port", 3333));
launchBrowser(options);
Page page = browser.newPage();
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.navigate("http://example.com"));
assertTrue(e.getMessage().contains("NS_ERROR_PROXY_CONNECTION_REFUSED"));
try {
page.navigate("http://example.com");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("NS_ERROR_PROXY_CONNECTION_REFUSED"));
}
}
}
@@ -19,7 +19,8 @@ package com.microsoft.playwright;
import org.junit.jupiter.api.Test;
import static com.microsoft.playwright.options.WaitUntilState.NETWORKIDLE;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class TestFrameNavigate extends TestBase {
@@ -42,11 +43,12 @@ public class TestFrameNavigate extends TestBase {
void shouldContinueAfterClientRedirect() {
server.setRoute("/frames/script.js", (httpExchange) -> {});
String url = server.PREFIX + "/frames/child-redirect.html";
TimeoutError e = assertThrows(TimeoutError.class, () -> {
try {
page.navigate(url, new Page.NavigateOptions().setTimeout(5000).setWaitUntil(NETWORKIDLE));
});
assertTrue(e.getMessage().contains("Timeout 5000ms exceeded."));
assertTrue(e.getMessage().contains("navigating to \"" + url +"\", waiting until \"networkidle\""));
} catch (TimeoutError e) {
assertTrue(e.getMessage().contains("Timeout 5000ms exceeded."));
assertTrue(e.getMessage().contains("navigating to \"" + url +"\", waiting until \"networkidle\""));
}
}
// TODO: not supported in sync api
@@ -24,7 +24,8 @@ import java.util.List;
import static com.microsoft.playwright.Utils.mapOf;
import static java.util.Arrays.asList;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class TestGeolocation extends TestBase {
@Test
@@ -40,10 +41,11 @@ public class TestGeolocation extends TestBase {
@Test
void shouldThrowWhenInvalidLongitude() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
context.setGeolocation(new Geolocation(10, 200));
});
assertTrue(e.getMessage().contains("geolocation.longitude: precondition -180 <= LONGITUDE <= 180 failed."));
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("geolocation.longitude: precondition -180 <= LONGITUDE <= 180 failed."));
}
}
@Test
@@ -6,8 +6,6 @@ import com.microsoft.playwright.options.RequestOptions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
@@ -148,8 +146,12 @@ public class TestGlobalFetch extends TestBase {
APIResponse response = request.get(server.PREFIX + "/simple.json");
assertEquals("{\"foo\": \"bar\"}\n", response.text());
request.dispose();
PlaywrightException e = assertThrows(PlaywrightException.class, () -> response.body());
assertTrue(e.getMessage().contains("Response has been disposed"), e.getMessage());
try {
response.body();
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Response has been disposed"), e.getMessage());
}
}
@Test
@@ -166,8 +168,12 @@ public class TestGlobalFetch extends TestBase {
void shouldSupportGlobalTimeoutOption() {
APIRequestContext request = playwright.request().newContext(new APIRequest.NewContextOptions().setTimeout(1));
server.setRoute("/empty.html", exchange -> {});
PlaywrightException e = assertThrows(PlaywrightException.class, () -> request.get(server.EMPTY_PAGE));
assertTrue(e.getMessage().contains("Request timed out after 1ms"), e.getMessage());
try {
request.get(server.EMPTY_PAGE);
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Request timed out after 1ms"), e.getMessage());
}
}
@@ -259,8 +265,12 @@ public class TestGlobalFetch extends TestBase {
assertEquals(0, body.length);
assertEquals("", response.text());
request.dispose();
PlaywrightException e = assertThrows(PlaywrightException.class, () -> response.body());
assertTrue(e.getMessage().contains("Response has been disposed"), e.getMessage());
try {
response.body();
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Response has been disposed"), e.getMessage());
}
}
@Test
@@ -311,73 +321,4 @@ public class TestGlobalFetch extends TestBase {
}
request.dispose();
}
@Test
void shouldReturnBodyForFailingRequests() {
APIRequestContext request = playwright.request().newContext();
for (String method : new String[] {"head", "put", "trace"}) {
server.setRoute("/empty.html", exchange -> {
exchange.getResponseHeaders().set("Content-type", "text/plain");
exchange.sendResponseHeaders(404, 10);
try (Writer writer = new OutputStreamWriter(exchange.getResponseBody())) {
writer.write("Not found.");
}
});
APIResponse response = request.fetch(server.EMPTY_PAGE, RequestOptions.create().setMethod(method));
assertEquals(404, response.status());
// HEAD response returns empty body in node http module.
assertEquals("head".equals(method) ? "" : "Not found.", response.text());
}
request.dispose();
}
@Test
void shouldThrowAnErrorWhenMaxRedirectsIsExceeded() {
server.setRedirect("/a/redirect1", "/b/c/redirect2");
server.setRedirect("/b/c/redirect2", "/b/c/redirect3");
server.setRedirect("/b/c/redirect3", "/b/c/redirect4");
server.setRedirect("/b/c/redirect4", "/simple.json");
APIRequestContext request = playwright.request().newContext();
for (String method : new String[] {"GET", "PUT", "POST", "OPTIONS", "HEAD", "PATCH"}) {
for (int maxRedirects = 1; maxRedirects < 4; maxRedirects++) {
int currMaxRedirects = maxRedirects;
PlaywrightException exception = assertThrows(PlaywrightException.class,
() -> request.fetch(server.PREFIX + "/a/redirect1",
RequestOptions.create().setMethod(method).setMaxRedirects(currMaxRedirects)));
assertTrue(exception.getMessage().contains("Max redirect count exceeded"), exception.getMessage());
}
}
request.dispose();
}
@Test
void shouldNotFollowRedirectsWhenMaxRedirectsIsSetTo0() {
server.setRedirect("/a/redirect1", "/b/c/redirect2");
server.setRedirect("/b/c/redirect2", "/simple.json");
APIRequestContext request = playwright.request().newContext();
for (String method : new String[] {"GET", "PUT", "POST", "OPTIONS", "HEAD", "PATCH"}) {
APIResponse response = request.fetch(server.PREFIX + "/a/redirect1",
RequestOptions.create().setMethod(method).setMaxRedirects(0));
assertEquals("/b/c/redirect2", response.headers().get("location"));
assertEquals(302, response.status());
}
request.dispose();
}
@Test
void shouldThrowAnErrorWhenMaxRedirectsIsLessThan0() {
server.setRedirect("/a/redirect1", "/b/c/redirect2");
server.setRedirect("/b/c/redirect2", "/simple.json");
APIRequestContext request = playwright.request().newContext();
for (String method : new String[] {"GET", "PUT", "POST", "OPTIONS", "HEAD", "PATCH"}) {
PlaywrightException exception = assertThrows(PlaywrightException.class,
() -> request.fetch(server.PREFIX + "/a/redirect1",
RequestOptions.create().setMethod(method).setMaxRedirects(-1)));
assertTrue(exception.getMessage().contains("'maxRedirects' should be greater than or equal to '0'"), exception.getMessage());
}
request.dispose();
}
}
@@ -1,46 +0,0 @@
package com.microsoft.playwright;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import java.util.stream.Collectors;
import static com.microsoft.playwright.Utils.mapOf;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class TestJavaSourceLocationInConstructor extends TestBase {
private static final String SRC_DIRS = System.getenv("PLAYWRIGHT_JAVA_SRC") == null ? "src/test/java" : System.getenv("PLAYWRIGHT_JAVA_SRC");
@Override
Playwright.CreateOptions playwrightOptions() {
return new Playwright.CreateOptions().setEnv(mapOf("PLAYWRIGHT_JAVA_SRC", SRC_DIRS));
}
@Test
void shouldSupportSourcesLocationPassedToPlaywrightCreate(@TempDir Path tmpDir) throws IOException {
context.tracing().start(new Tracing.StartOptions().setSources(true));
page.navigate(server.EMPTY_PAGE);
page.setContent("<button>Click</button>");
page.click("'Click'");
Path trace = tmpDir.resolve("trace1.zip");
context.tracing().stop(new Tracing.StopOptions().setPath(trace));
Map<String, byte[]> entries = Utils.parseZip(trace);
Map<String, byte[]> sources = entries.entrySet().stream().filter(e -> e.getKey().endsWith(".txt")).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
assertEquals(1, sources.size());
String path = getClass().getName().replace('.', File.separatorChar);
String[] srcRoots = SRC_DIRS.split(File.pathSeparator);
// Resolve in the last specified source dir.
Path sourceFile = Paths.get(srcRoots[srcRoots.length - 1], path + ".java");
byte[] thisFile = Files.readAllBytes(sourceFile);
assertEquals(new String(thisFile, UTF_8), new String(sources.values().iterator().next(), UTF_8));
}
}
@@ -17,7 +17,6 @@
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;
@@ -63,12 +62,14 @@ public class TestLocatorAssertions extends TestBase {
void containsTextWRegexFail() {
page.setContent("<div id=node>Text content</div>");
Locator locator = page.locator("#node");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).containsText(Pattern.compile("ex2"), new LocatorAssertions.ContainsTextOptions().setTimeout(1000));
});
assertEquals("ex2", e.getExpected().getStringRepresentation());
assertEquals("Text content", e.getActual().getValue());
assertTrue(e.getMessage().contains("Locator expected to contain regex"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("ex2", e.getExpected().getStringRepresentation());
assertEquals("Text content", e.getActual().getValue());
assertTrue(e.getMessage().contains("Locator expected to contain regex"), e.getMessage());
}
}
@Test
@@ -110,12 +111,14 @@ public class TestLocatorAssertions extends TestBase {
void hasTextWRegexFail() {
page.setContent("<div id=node>Text content</div>");
Locator locator = page.locator("#node");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).hasText(Pattern.compile("Text 2"), new LocatorAssertions.HasTextOptions().setTimeout(1000));
});
assertEquals("Text 2", e.getExpected().getStringRepresentation());
assertEquals("Text content", e.getActual().getValue());
assertTrue(e.getMessage().contains("Locator expected to have text matching regex"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("Text 2", e.getExpected().getStringRepresentation());
assertEquals("Text content", e.getActual().getValue());
assertTrue(e.getMessage().contains("Locator expected to have text matching regex"), e.getMessage());
}
}
@Test
@@ -135,12 +138,14 @@ public class TestLocatorAssertions extends TestBase {
page.setContent("<div id=node>Text content</div>");
Locator locator = page.locator("#node");
// Should normalize whitespace.
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).hasText("Text", new LocatorAssertions.HasTextOptions().setTimeout(1000));
});
assertEquals("Text", e.getExpected().getStringRepresentation());
assertEquals("Text content", e.getActual().getValue());
assertTrue(e.getMessage().contains("Locator expected to have text"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("Text", e.getExpected().getStringRepresentation());
assertEquals("Text content", e.getActual().getValue());
assertTrue(e.getMessage().contains("Locator expected to have text"), e.getMessage());
}
}
@Test
@@ -189,12 +194,14 @@ public class TestLocatorAssertions extends TestBase {
page.setContent("<div></div>");
Locator locator = page.locator("p");
// Should normalize whitespace.
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).not().hasText(new String[] {}, new LocatorAssertions.HasTextOptions().setTimeout(1000));
});
assertEquals("[]", e.getExpected().getStringRepresentation());
assertEquals("null", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected not to have text"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("[]", e.getExpected().getStringRepresentation());
assertEquals("null", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected not to have text"), e.getMessage());
}
}
@Test
@@ -215,14 +222,16 @@ public class TestLocatorAssertions extends TestBase {
page.evaluate("setTimeout(() => {\n" +
" div.innerHTML = \"<p>Text 1</p><p>Text 2</p>\";\n" +
"}, 100);");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
// Should normalize whitespace.
assertThat(locator).hasText(new String[] {"Text 1", "Text 3", "Extra"}, new LocatorAssertions.HasTextOptions().setTimeout(1000));
});
assertEquals("[Text 1, Text 3, Extra]", e.getExpected().getStringRepresentation());
assertEquals("[Text 1, Text 3]", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have text: [Text 1, Text 3, Extra]"), e.getMessage());
assertTrue(e.getMessage().contains("Received: [Text 1, Text 3]"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("[Text 1, Text 3, Extra]", e.getExpected().getStringRepresentation());
assertEquals("[Text 1, Text 3]", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have text: [Text 1, Text 3, Extra]"), e.getMessage());
assertTrue(e.getMessage().contains("Received: [Text 1, Text 3]"), e.getMessage());
}
}
@Test
@@ -237,13 +246,15 @@ public class TestLocatorAssertions extends TestBase {
void hasTextWRegExArrayFail() {
page.setContent("<div>Text 1</div><div>Text 3</div>");
Locator locator = page.locator("div");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
// Should normalize whitespace.
assertThat(locator).hasText(new Pattern[] {Pattern.compile( "Text 1"), Pattern.compile("Text \\d"), Pattern.compile("Extra")}, new LocatorAssertions.HasTextOptions().setTimeout(1000));
});
assertEquals("[Text 1, Text \\d, Extra]", e.getExpected().getStringRepresentation());
assertEquals("[Text 1, Text 3]", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have text"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("[Text 1, Text \\d, Extra]", e.getExpected().getStringRepresentation());
assertEquals("[Text 1, Text 3]", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have text"), e.getMessage());
}
}
@Test
@@ -257,12 +268,14 @@ public class TestLocatorAssertions extends TestBase {
void hasAttributeTextFail() {
page.setContent("<div id=node>Text content</div>");
Locator locator = page.locator("#node");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).hasAttribute("id", "foo", new LocatorAssertions.HasAttributeOptions().setTimeout(1000));
});
assertEquals("foo", e.getExpected().getStringRepresentation());
assertEquals("node", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have attribute 'id': foo\nReceived: node"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("foo", e.getExpected().getStringRepresentation());
assertEquals("node", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have attribute 'id': foo\nReceived: node"), e.getMessage());
}
}
@Test
@@ -276,12 +289,14 @@ public class TestLocatorAssertions extends TestBase {
void hasAttributeRegExpFail() {
page.setContent("<div id=node>Text content</div>");
Locator locator = page.locator("#node");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).hasAttribute("id", Pattern.compile(".Nod.."), new LocatorAssertions.HasAttributeOptions().setTimeout(1000));
});
assertEquals(".Nod..", e.getExpected().getStringRepresentation());
assertEquals("node", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have attribute 'id' matching regex: .Nod..\nReceived: node"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals(".Nod..", e.getExpected().getStringRepresentation());
assertEquals("node", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have attribute 'id' matching regex: .Nod..\nReceived: node"), e.getMessage());
}
}
@Test
@@ -295,12 +310,14 @@ public class TestLocatorAssertions extends TestBase {
void hasClassTextFail() {
page.setContent("<div class=\"bar baz\"></div>");
Locator locator = page.locator("div");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).hasClass("foo bar baz", new LocatorAssertions.HasClassOptions().setTimeout(1000));
});
assertEquals("foo bar baz", e.getExpected().getStringRepresentation());
assertEquals("bar baz", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have class"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("foo bar baz", e.getExpected().getStringRepresentation());
assertEquals("bar baz", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have class"), e.getMessage());
}
}
@Test
@@ -314,12 +331,14 @@ public class TestLocatorAssertions extends TestBase {
void hasClassRegExpFail() {
page.setContent("<div class=\"bar baz\"></div>");
Locator locator = page.locator("div");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).hasClass(Pattern.compile("foo Z.*"), new LocatorAssertions.HasClassOptions().setTimeout(1000));
});
assertEquals("foo Z.*", e.getExpected().getStringRepresentation());
assertEquals("bar baz", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have class matching regex"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("foo Z.*", e.getExpected().getStringRepresentation());
assertEquals("bar baz", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have class matching regex"), e.getMessage());
}
}
@Test
@@ -333,12 +352,14 @@ public class TestLocatorAssertions extends TestBase {
void hasClassTextArrayFail() {
page.setContent("<div class=\"foo\"></div><div class=\"bar\"></div><div class=\"baz\"></div>");
Locator locator = page.locator("div");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).hasClass(new String[] {"foo", "bar", "missing"}, new LocatorAssertions.HasClassOptions().setTimeout(1000));
});
assertEquals("[foo, bar, missing]", e.getExpected().getStringRepresentation());
assertEquals("[foo, bar, baz]", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have class"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("[foo, bar, missing]", e.getExpected().getStringRepresentation());
assertEquals("[foo, bar, baz]", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have class"), e.getMessage());
}
}
@Test
@@ -352,12 +373,14 @@ public class TestLocatorAssertions extends TestBase {
void hasClassRegExpArrayFail() {
page.setContent("<div class=\"foo\"></div><div class=\"bar\"></div><div class=\"baz\"></div>");
Locator locator = page.locator("div");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).hasClass(new Pattern[] {Pattern.compile("fo.*"), Pattern.compile(".ar"), Pattern.compile("baz"), Pattern.compile("extra")}, new LocatorAssertions.HasClassOptions().setTimeout(1000));
});
assertEquals("[fo.*, .ar, baz, extra]", e.getExpected().getStringRepresentation());
assertEquals("[foo, bar, baz]", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have class matching regex"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("[fo.*, .ar, baz, extra]", e.getExpected().getStringRepresentation());
assertEquals("[foo, bar, baz]", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have class matching regex"), e.getMessage());
}
}
@Test
@@ -371,12 +394,14 @@ public class TestLocatorAssertions extends TestBase {
void hasCountFail() {
page.setContent("<select><option>One</option><option>Two</option></select>");
Locator locator = page.locator("option");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).hasCount(1, new LocatorAssertions.HasCountOptions().setTimeout(1000));
});
assertEquals("1", e.getExpected().getStringRepresentation());
assertEquals("2", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have count"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("1", e.getExpected().getStringRepresentation());
assertEquals("2", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have count"), e.getMessage());
}
}
@Test
@@ -398,12 +423,14 @@ public class TestLocatorAssertions extends TestBase {
void hasCSSFail() {
page.setContent("<div id=node style='color: rgb(255, 0, 0)'>Text content</div>");
Locator locator = page.locator("#node");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).hasCSS("color", "red", new LocatorAssertions.HasCSSOptions().setTimeout(1000));
});
assertEquals("red", e.getExpected().getStringRepresentation());
assertEquals("rgb(255, 0, 0)", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have CSS property 'color'"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("red", e.getExpected().getStringRepresentation());
assertEquals("rgb(255, 0, 0)", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have CSS property 'color'"), e.getMessage());
}
}
@Test
@@ -417,12 +444,14 @@ public class TestLocatorAssertions extends TestBase {
void hasCSSRegExFail() {
page.setContent("<div id=node style='color: rgb(255, 0, 0)'>Text content</div>");
Locator locator = page.locator("#node");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).hasCSS("color", Pattern.compile("red"), new LocatorAssertions.HasCSSOptions().setTimeout(1000));
});
assertEquals("red", e.getExpected().getStringRepresentation());
assertEquals("rgb(255, 0, 0)", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have CSS property 'color' matching regex"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("red", e.getExpected().getStringRepresentation());
assertEquals("rgb(255, 0, 0)", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have CSS property 'color' matching regex"), e.getMessage());
}
}
@Test
@@ -436,12 +465,14 @@ public class TestLocatorAssertions extends TestBase {
void hasIdFail() {
page.setContent("<div id=node>Text content</div>");
Locator locator = page.locator("#node");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).hasId("foo", new LocatorAssertions.HasIdOptions().setTimeout(1000));
});
assertEquals("foo", e.getExpected().getStringRepresentation());
assertEquals("node", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have ID"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("foo", e.getExpected().getStringRepresentation());
assertEquals("node", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have ID"), e.getMessage());
}
}
@Test
@@ -457,12 +488,14 @@ public class TestLocatorAssertions extends TestBase {
page.setContent("<div id=node>Text content</div>");
Locator locator = page.locator("#node");
page.evalOnSelector("div", "e => e.foo = 2021");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).hasJSProperty("foo", 1, new LocatorAssertions.HasJSPropertyOptions().setTimeout(1000));
});
assertEquals("1", e.getExpected().getStringRepresentation());
assertEquals("2021", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have JavaScript property 'foo'"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("1", e.getExpected().getStringRepresentation());
assertEquals("2021", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have JavaScript property 'foo'"), e.getMessage());
}
}
@Test
@@ -470,24 +503,28 @@ public class TestLocatorAssertions extends TestBase {
page.setContent("<div id=node>Text content</div>");
Locator locator = page.locator("#node");
page.evalOnSelector("div", "e => e.foo = { a: 1, b: 'string' }");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).hasJSProperty("foo", mapOf("a", 2), new LocatorAssertions.HasJSPropertyOptions().setTimeout(1000));
});
assertEquals("{a=2}", e.getExpected().getStringRepresentation());
assertEquals("{a=1, b=string}", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have JavaScript property 'foo'"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("{a=2}", e.getExpected().getStringRepresentation());
assertEquals("{a=1, b=string}", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have JavaScript property 'foo'"), e.getMessage());
}
}
@Test
void hasJSPropertyStringFail() {
page.setContent("<div id=node>Text content</div>");
Locator locator = page.locator("#node");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).hasJSProperty("id", "foo", new LocatorAssertions.HasJSPropertyOptions().setTimeout(1000));
});
assertEquals("foo", e.getExpected().getStringRepresentation());
assertEquals("node", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have JavaScript property 'id'"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("foo", e.getExpected().getStringRepresentation());
assertEquals("node", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have JavaScript property 'id'"), e.getMessage());
}
}
@Test
@@ -503,12 +540,14 @@ public class TestLocatorAssertions extends TestBase {
page.setContent("<input id=node></input>");
Locator locator = page.locator("#node");
locator.fill("Text content");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).hasValue("Text2", new LocatorAssertions.HasValueOptions().setTimeout(1000));
});
assertEquals("Text2", e.getExpected().getStringRepresentation());
assertEquals("Text content", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have value"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("Text2", e.getExpected().getStringRepresentation());
assertEquals("Text content", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have value"), e.getMessage());
}
}
@Test
@@ -532,12 +571,14 @@ public class TestLocatorAssertions extends TestBase {
page.setContent("<input id=node></input>");
Locator locator = page.locator("#node");
locator.fill("Text content");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).hasValue(Pattern.compile("Text2"), new LocatorAssertions.HasValueOptions().setTimeout(1000));
});
assertEquals("Text2", e.getExpected().getStringRepresentation());
assertEquals("Text content", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have value matching regex"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("Text2", e.getExpected().getStringRepresentation());
assertEquals("Text content", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have value matching regex"), e.getMessage());
}
}
@Test
@@ -573,12 +614,14 @@ public class TestLocatorAssertions extends TestBase {
" </select>");
Locator locator = page.locator("select");
locator.selectOption(new String[] {"RR", "GG"});
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).hasValues(new String[]{"R", "G"}, new LocatorAssertions.HasValuesOptions().setTimeout(1000));
});
assertEquals("[R, G]", e.getExpected().getStringRepresentation());
assertEquals("[RR, GG]", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have values"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("[R, G]", e.getExpected().getStringRepresentation());
assertEquals("[RR, GG]", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have values"), e.getMessage());
}
}
@Test
@@ -602,12 +645,14 @@ public class TestLocatorAssertions extends TestBase {
" </select>");
Locator locator = page.locator("select");
locator.selectOption(new String[] {"B"}, new Locator.SelectOptionOptions().setTimeout(1000));
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).hasValues(new Pattern[]{ Pattern.compile("R"), Pattern.compile("G")});
});
assertEquals("[R, G]", e.getExpected().getStringRepresentation());
assertEquals("[B]", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have values matching regex"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("[R, G]", e.getExpected().getStringRepresentation());
assertEquals("[B]", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected to have values matching regex"), e.getMessage());
}
}
@Test
@@ -619,20 +664,24 @@ public class TestLocatorAssertions extends TestBase {
" </select>");
Locator locator = page.locator("select");
locator.selectOption(new String[] {"B"});
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
assertThat(locator).hasValues(new Pattern[]{ Pattern.compile("R"), Pattern.compile("G")});
});
assertTrue(e.getMessage().contains("Not a select element with a multiple attribute"), e.getMessage());
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Not a select element with a multiple attribute"), e.getMessage());
}
}
@Test
void hasValuesFailsWhenNotASelectElement() {
page.setContent("<input value=\"foo\" />");
Locator locator = page.locator("input");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
assertThat(locator).hasValues(new Pattern[]{ Pattern.compile("R"), Pattern.compile("G")}, new LocatorAssertions.HasValuesOptions().setTimeout(1000));
});
assertTrue(e.getMessage().contains("Not a select element with a multiple attribute"), e.getMessage());
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Not a select element with a multiple attribute"), e.getMessage());
}
}
@Test
@@ -646,24 +695,28 @@ public class TestLocatorAssertions extends TestBase {
void isCheckedFail() {
page.setContent("<input type=checkbox></input>");
Locator locator = page.locator("input");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).isChecked(new LocatorAssertions.IsCheckedOptions().setTimeout(1000));
});
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected to be checked"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected to be checked"), e.getMessage());
}
}
@Test
void notIsCheckedFail() {
page.setContent("<input type=checkbox checked></input>");
Locator locator = page.locator("input");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).not().isChecked(new LocatorAssertions.IsCheckedOptions().setTimeout(1000));
});
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected not to be checked"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected not to be checked"), e.getMessage());
}
}
@Test
@@ -684,24 +737,28 @@ public class TestLocatorAssertions extends TestBase {
void isDisabledFail() {
page.setContent("<button>Text</button>");
Locator locator = page.locator("button");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).isDisabled(new LocatorAssertions.IsDisabledOptions().setTimeout(1000));
});
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected to be disabled"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected to be disabled"), e.getMessage());
}
}
@Test
void notIsDisabledFail() {
page.setContent("<button disabled>Text</button>");
Locator locator = page.locator("button");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).not().isDisabled(new LocatorAssertions.IsDisabledOptions().setTimeout(1000));
});
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected not to be disabled"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected not to be disabled"), e.getMessage());
}
}
@Test
@@ -715,53 +772,30 @@ public class TestLocatorAssertions extends TestBase {
void isEditableFail() {
page.setContent("<input disabled></input>");
Locator locator = page.locator("input");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).isEditable(new LocatorAssertions.IsEditableOptions().setTimeout(1000));
});
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected to be editable"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected to be editable"), e.getMessage());
}
}
@Test
void notIsEditableFail() {
page.setContent("<input></input>");
Locator locator = page.locator("input");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).not().isEditable(new LocatorAssertions.IsEditableOptions().setTimeout(1000));
});
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected not to be editable"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected not to be editable"), e.getMessage());
}
}
@Test
void isEditableWithNot() {
page.setContent("<input readonly></input>");
Locator locator = page.locator("input");
assertThat(locator).not().isEditable();
}
@Test
void isEditableWithEditableTrue() {
page.setContent("<input></input>");
Locator locator = page.locator("input");
assertThat(locator).isEditable(new LocatorAssertions.IsEditableOptions().setEditable(true));
}
@Test
void isEditableWithEditableFalse() {
page.setContent("<input readonly></input>");
Locator locator = page.locator("input");
assertThat(locator).isEditable(new LocatorAssertions.IsEditableOptions().setEditable(false));
}
@Test
void isEditableWithNotAndEditableFalse() {
page.setContent("<input></input>");
Locator locator = page.locator("input");
assertThat(locator).not().isEditable(new LocatorAssertions.IsEditableOptions().setEditable(false));
}
@Test
void isEmptyPass() {
@@ -774,24 +808,28 @@ public class TestLocatorAssertions extends TestBase {
void isEmptyFail() {
page.setContent("<input value=text></input>");
Locator locator = page.locator("input");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).isEmpty(new LocatorAssertions.IsEmptyOptions().setTimeout(1000));
});
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected to be empty"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected to be empty"), e.getMessage());
}
}
@Test
void notIsEmptyFail() {
page.setContent("<input></input>");
Locator locator = page.locator("input");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).not().isEmpty(new LocatorAssertions.IsEmptyOptions().setTimeout(1000));
});
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected not to be empty"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected not to be empty"), e.getMessage());
}
}
@Test
@@ -805,65 +843,28 @@ public class TestLocatorAssertions extends TestBase {
void isEnabledFail() {
page.setContent("<button disabled>Text</button>");
Locator locator = page.locator("button");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).isEnabled(new LocatorAssertions.IsEnabledOptions().setTimeout(1000));
});
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected to be enabled"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected to be enabled"), e.getMessage());
}
}
@Test
void notIsEnabledFail() {
page.setContent("<button>Text</button>");
Locator locator = page.locator("button");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).not().isEnabled(new LocatorAssertions.IsEnabledOptions().setTimeout(1000));
});
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected not to be enabled"), e.getMessage());
}
@Test
void isEnabledTrue() {
page.setContent("<button>Text</button>");
Locator locator = page.locator("button");
assertThat(locator).isEnabled(new LocatorAssertions.IsEnabledOptions().setEnabled(true));
}
@Test
void isEnabledFalse() {
page.setContent("<button disabled>Text</button>");
Locator locator = page.locator("button");
assertThat(locator).isEnabled(new LocatorAssertions.IsEnabledOptions().setEnabled(false));
}
@Test
void isEnabledEventually() {
page.setContent("<button disabled>Text</button>");
Locator locator = page.locator("button");
locator.evaluate("e => setTimeout(() => {\n" +
" e.removeAttribute('disabled');\n" +
"}, 500);\n");
assertThat(locator).isEnabled();
}
@Test
void isEnabledEventuallyWithNot() {
page.setContent("<button>Text</button>");
Locator locator = page.locator("button");
locator.evaluate("e => setTimeout(() => {\n" +
" e.setAttribute('disabled', '');\n" +
"}, 500);\n");
assertThat(locator).not().isEnabled();
}
@Test
void isEnabledWithNotAndEnabledFalse() {
page.setContent("<button>Text</button>");
Locator locator = page.locator("button");
assertThat(locator).not().isEnabled(new LocatorAssertions.IsEnabledOptions().setEnabled(false));
fail("did not throw");
} catch (AssertionFailedError e) {
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected not to be enabled"), e.getMessage());
}
}
@Test
@@ -878,12 +879,14 @@ public class TestLocatorAssertions extends TestBase {
void isFocusedFail() {
page.setContent("<input></input>");
Locator locator = page.locator("input");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).isFocused(new LocatorAssertions.IsFocusedOptions().setTimeout(1000));
});
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected to be focused"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected to be focused"), e.getMessage());
}
}
@Test
@@ -891,12 +894,14 @@ public class TestLocatorAssertions extends TestBase {
page.setContent("<input></input>");
Locator locator = page.locator("input");
locator.focus();
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).not().isFocused(new LocatorAssertions.IsFocusedOptions().setTimeout(1000));
});
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected not to be focused"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected not to be focused"), e.getMessage());
}
}
@Test
@@ -910,24 +915,28 @@ public class TestLocatorAssertions extends TestBase {
void isHiddenFail() {
page.setContent("<button></button>");
Locator locator = page.locator("button");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).isHidden(new LocatorAssertions.IsHiddenOptions().setTimeout(1000));
});
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected to be hidden"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected to be hidden"), e.getMessage());
}
}
@Test
void notIsHiddenFail() {
page.setContent("<button style='display: none'></button>");
Locator locator = page.locator("button");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).not().isHidden(new LocatorAssertions.IsHiddenOptions().setTimeout(1000));
});
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected not to be hidden"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected not to be hidden"), e.getMessage());
}
}
@Test
@@ -941,65 +950,28 @@ public class TestLocatorAssertions extends TestBase {
void isVisibleFail() {
page.setContent("<input style='display: none'></input>");
Locator locator = page.locator("input");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).isVisible(new LocatorAssertions.IsVisibleOptions().setTimeout(1000));
});
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected to be visible"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected to be visible"), e.getMessage());
}
}
@Test
void notIsVisibleFail() {
page.setContent("<input></input>");
Locator locator = page.locator("input");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(locator).not().isVisible(new LocatorAssertions.IsVisibleOptions().setTimeout(1000));
});
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected not to be visible"), e.getMessage());
}
@Test
void isVisibleWithTrue() {
page.setContent("<button>hello</button>");
Locator locator = page.locator("button");
assertThat(locator).isVisible(new LocatorAssertions.IsVisibleOptions().setVisible(true));
}
@Test
void isVisibleWithFalse() {
page.setContent("<button hidden>hello</button>");
Locator locator = page.locator("button");
assertThat(locator).isVisible(new LocatorAssertions.IsVisibleOptions().setVisible(false));
}
@Test
void isVisibleWithNotAndFalse() {
page.setContent("<button>hello</button>");
Locator locator = page.locator("button");
assertThat(locator).not().isVisible(new LocatorAssertions.IsVisibleOptions().setVisible(false));
}
@Test
void isVisibleEventually() {
page.setContent("<div></div>");
Locator locator = page.locator("span");
page.evalOnSelector("div", "div => setTimeout(() => {\n" +
" div.innerHTML = '<span>Hello</span>';\n" +
" }, 10);");
assertThat(locator).isVisible();
}
@Test
void isVisibleEventuallyWithNot() {
page.setContent("<div><span>Hello</span></div>");
Locator locator = page.locator("span");
page.evalOnSelector("span", "span => setTimeout(() => {\n" +
" span.textContent = '';\n" +
" }, 10);");
assertThat(locator).not().isVisible();
fail("did not throw");
} catch (AssertionFailedError e) {
assertNull(e.getExpected());
assertNull(e.getActual());
assertTrue(e.getMessage().contains("Locator expected not to be visible"), e.getMessage());
}
}
@Test
@@ -1008,35 +980,4 @@ 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);
}
}
@@ -61,13 +61,19 @@ public class TestLocatorConvenience extends TestBase {
Locator locator = page.locator("#input");
assertEquals("input value", locator.inputValue());
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.inputValue("#inner"));
assertTrue(e.getMessage().contains("Node is not an <input>, <textarea> or <select> element"), e.getMessage());
e = assertThrows(PlaywrightException.class, () -> {
try {
page.inputValue("#inner");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Node is not an <input>, <textarea> or <select> element"), e.getMessage());
}
try {
Locator locator2 = page.locator("#inner");
locator2.inputValue();
});
assertTrue(e.getMessage().contains("Node is not an <input>, <textarea> or <select> element"), e.getMessage());
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Node is not an <input>, <textarea> or <select> element"), e.getMessage());
}
}
@Test
@@ -89,12 +95,19 @@ public class TestLocatorConvenience extends TestBase {
@Test
void innerTextShouldThrow() {
page.setContent("<svg>text</svg>");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.innerText("svg"));
assertTrue(e.getMessage().contains("Node is not an HTMLElement"), e.getMessage());
try {
page.innerText("svg");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Node is not an HTMLElement"), e.getMessage());
}
Locator locator = page.locator("svg");
e = assertThrows(PlaywrightException.class, () -> locator.innerText());
assertTrue(e.getMessage().contains("Node is not an HTMLElement"), e.getMessage());
try {
locator.innerText();
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Node is not an HTMLElement"), e.getMessage());
}
}
@Test
@@ -171,8 +184,12 @@ public class TestLocatorConvenience extends TestBase {
element.evaluate("input => input.checked = false");
assertFalse(element.isChecked());
assertFalse(page.isChecked("input"));
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.isChecked("div"));
assertTrue(e.getMessage().contains("Not a checkbox or radio button"));
try {
page.isChecked("div");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Not a checkbox or radio button"));
}
}
@Test
@@ -99,10 +99,12 @@ public class TestLocatorFrame extends TestBase {
@Test
void shouldWaitForFrame() {
page.navigate(server.EMPTY_PAGE);
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
page.frameLocator("iframe").locator("span").click(new Locator.ClickOptions().setTimeout(300));
});
assertTrue(e.getMessage().contains("waiting for frame \"iframe\""), e.getMessage());
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("waiting for frame \"iframe\""), e.getMessage());
}
}
@Test
@@ -204,9 +206,13 @@ public class TestLocatorFrame extends TestBase {
routeIframe(page);
page.setContent("<div></div>");
Locator button = page.frameLocator("div").locator("button");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> button.waitFor());
assertTrue(e.getMessage().contains("<div></div>"), e.getMessage());
assertTrue(e.getMessage().contains("<iframe> was expected"), e.getMessage());
try {
button.waitFor();
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("<div></div>"), e.getMessage());
assertTrue(e.getMessage().contains("<iframe> was expected"), e.getMessage());
}
}
@Test
@@ -225,8 +231,12 @@ public class TestLocatorFrame extends TestBase {
routeAmbiguous(page);
page.navigate(server.EMPTY_PAGE);
Locator button = page.locator("body").frameLocator("iframe").locator("button");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> button.waitFor());
assertTrue(e.getMessage().contains("Error: strict mode violation: \"body >> iframe\" resolved to 3 elements"), e.getMessage());
try {
button.waitFor();
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Error: strict mode violation: \"body >> iframe\" resolved to 3 elements"), e.getMessage());
}
}
@Test
@@ -19,9 +19,8 @@ package com.microsoft.playwright;
import com.microsoft.playwright.options.WaitForSelectorState;
import org.junit.jupiter.api.Test;
import java.util.regex.Pattern;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class TestLocatorMisc extends TestBase{
@Test
@@ -50,20 +49,4 @@ 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) {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
locator.click(new Locator.ClickOptions().setTimeout(100));
});
assertTrue(e.getMessage().contains("Драматург"), e.getMessage());
}
}
}
@@ -67,8 +67,12 @@ public class TestNetworkResponse extends TestBase {
assertNotNull(redirectedFrom);
Response redirected = redirectedFrom.response();
assertEquals(302, redirected.status());
PlaywrightException e = assertThrows(PlaywrightException.class, () -> redirected.text());
assertTrue(e.getMessage().contains("Response body is unavailable for redirect responses"));
try {
redirected.text();
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Response body is unavailable for redirect responses"));
}
}
@Test
@@ -35,12 +35,14 @@ public class TestPageAssertions extends TestBase {
@Test
void hasURLTextFail() {
page.navigate("data:text/html,<div>B</div>");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(page).hasURL("foo", new PageAssertions.HasURLOptions().setTimeout(1_000));
});
assertEquals("foo", e.getExpected().getValue());
assertEquals("data:text/html,<div>B</div>", e.getActual().getValue());
assertTrue(e.getMessage().contains("Page URL expected to be"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("foo", e.getExpected().getValue());
assertEquals("data:text/html,<div>B</div>", e.getActual().getValue());
assertTrue(e.getMessage().contains("Page URL expected to be"), e.getMessage());
}
}
@Test
@@ -67,12 +69,14 @@ public class TestPageAssertions extends TestBase {
@Test
void hasURLRegexFail() {
page.navigate(server.EMPTY_PAGE);
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(page).hasURL(Pattern.compile(".*foo.*"), new PageAssertions.HasURLOptions().setTimeout(1_000));
});
assertEquals(".*foo.*", e.getExpected().getStringRepresentation());
assertEquals(server.EMPTY_PAGE, e.getActual().getValue());
assertTrue(e.getMessage().contains("Page URL expected to match regex"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals(".*foo.*", e.getExpected().getStringRepresentation());
assertEquals(server.EMPTY_PAGE, e.getActual().getValue());
assertTrue(e.getMessage().contains("Page URL expected to match regex"), e.getMessage());
}
}
@Test
@@ -96,12 +100,14 @@ public class TestPageAssertions extends TestBase {
@Test
void hasTitleTextFail() {
page.navigate(server.PREFIX + "/title.html");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(page).hasTitle("foo", new PageAssertions.HasTitleOptions().setTimeout(1_000));
});
assertEquals("foo", e.getExpected().getValue());
assertEquals("Woof-Woof", e.getActual().getValue());
assertTrue(e.getMessage().contains("Page title expected to be: foo\nReceived: Woof-Woof"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("foo", e.getExpected().getValue());
assertEquals("Woof-Woof", e.getActual().getValue());
assertTrue(e.getMessage().contains("Page title expected to be: foo\nReceived: Woof-Woof"), e.getMessage());
}
}
@Test
@@ -113,12 +119,14 @@ public class TestPageAssertions extends TestBase {
@Test
void hasTitleRegexFail() {
page.navigate(server.PREFIX + "/title.html");
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
try {
assertThat(page).hasTitle(Pattern.compile("^foo[AB]"), new PageAssertions.HasTitleOptions().setTimeout(1_000));
});
assertEquals("^foo[AB]", e.getExpected().getStringRepresentation());
assertEquals("Woof-Woof", e.getActual().getValue());
assertTrue(e.getMessage().contains("Page title expected to match regex: ^foo[AB]\nReceived: Woof-Woof"), e.getMessage());
fail("did not throw");
} catch (AssertionFailedError e) {
assertEquals("^foo[AB]", e.getExpected().getStringRepresentation());
assertEquals("Woof-Woof", e.getActual().getValue());
assertTrue(e.getMessage().contains("Page title expected to match regex: ^foo[AB]\nReceived: Woof-Woof"), e.getMessage());
}
}
@Test
@@ -35,10 +35,12 @@ public class TestPageBasic extends TestBase {
void shouldRejectAllPromisesWhenPageIsClosed() {
Page newPage = context.newPage();
newPage.close();
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
newPage.evaluate("() => new Promise(r => {})");
});
assertTrue(e.getMessage().contains("Target page, context or browser has been closed"), e.getMessage());
fail("evaluate should throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Target closed"), e.getMessage());
}
}
@Test
@@ -106,17 +108,21 @@ public class TestPageBasic extends TestBase {
@Test
void shouldTerminateNetworkWaiters() {
Page newPage = context.newPage();
PlaywrightException e1 = assertThrows(PlaywrightException.class, () -> {
try {
newPage.waitForResponse("**", () -> {
PlaywrightException e2 = assertThrows(PlaywrightException.class, () -> {
try {
newPage.waitForRequest(server.EMPTY_PAGE, () -> newPage.close());
});
assertTrue(e2.getMessage().contains("Page closed"));
assertFalse(e2.getMessage().contains("Timeout"));
fail("waitForRequest() should throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Page closed"));
assertFalse(e.getMessage().contains("Timeout"));
}
});
});
assertTrue(e1.getMessage().contains("Page closed"));
assertFalse(e1.getMessage().contains("Timeout"));
fail("waitForResponse() should throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Page closed"));
assertFalse(e.getMessage().contains("Timeout"));
}
}
@Test
@@ -19,12 +19,7 @@ package com.microsoft.playwright;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledIf;
import java.time.*;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.Date;
import java.net.MalformedURLException;
import java.net.URL;
import static com.microsoft.playwright.Utils.mapOf;
import static java.util.Arrays.asList;
@@ -157,13 +152,15 @@ public class TestPageEvaluate extends TestBase {
@Test
void shouldThrowWhenEvaluationTriggersReload() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
page.evaluate("() => {\n" +
" location.reload();\n" +
" return new Promise(() => { });\n" +
"}");
});
assertTrue(e.getMessage().contains("navigation"));
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("navigation"));
}
}
@Test
@@ -206,20 +203,32 @@ public class TestPageEvaluate extends TestBase {
@Test
void shouldRejectPromiseWithException() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.evaluate("() => not_existing_object.property"));
assertTrue(e.getMessage().contains("not_existing_object"));
try {
page.evaluate("() => not_existing_object.property");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("not_existing_object"));
}
}
@Test
void shouldSupportThrownStringsAsErrorMessages() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.evaluate("() => { throw 'qwerty'; }"));
assertTrue(e.getMessage().contains("qwerty"));
try {
page.evaluate("() => { throw 'qwerty'; }");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("qwerty"));
}
}
@Test
void shouldSupportThrownNumbersAsErrorMessages() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.evaluate("() => { throw 100500; }"));
assertTrue(e.getMessage().contains("100500"));
try {
page.evaluate("() => { throw 100500; }");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("100500"));
}
}
@Test
@@ -343,12 +352,14 @@ public class TestPageEvaluate extends TestBase {
@Test
void shouldBeAbleToThrowATrickyError() {
String errorText = "My error";
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
page.evaluate("errorText => {\n" +
" throw new Error(errorText);\n" +
"}", errorText);
});
assertTrue(e.getMessage().contains(errorText));
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains(errorText));
}
}
@Test
@@ -383,8 +394,12 @@ public class TestPageEvaluate extends TestBase {
ElementHandle element = page.querySelector("section");
assertNotNull(element);
element.dispose();
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.evaluate("e => e.textContent", element));
assertTrue(e.getMessage().contains("JSHandle is disposed"));
try {
page.evaluate("e => e.textContent", element);
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("JSHandle is disposed"));
}
}
@Test
@@ -398,7 +413,7 @@ public class TestPageEvaluate extends TestBase {
@Test
void shouldThrowANiceErrorAfterANavigation() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
page.waitForNavigation(() -> {
page.evaluate("() => {\n" +
" const promise = new Promise(f => window['__resolve'] = f);\n" +
@@ -407,8 +422,9 @@ public class TestPageEvaluate extends TestBase {
" return promise;\n" +
"}");
});
});
assertTrue(e.getMessage().contains("navigation"));
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("navigation"));
}
}
@Test
@@ -457,12 +473,14 @@ public class TestPageEvaluate extends TestBase {
@Test
void shouldThrowErrorWithDetailedInformationOnExceptionInsidePromise() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
page.evaluate("() => new Promise(() => {\n" +
" throw new Error('Error in promise');\n" +
"})");
});
assertTrue(e.getMessage().contains("Error in promise"));
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Error in promise"));
}
}
@Test
@@ -500,7 +518,7 @@ public class TestPageEvaluate extends TestBase {
@Test
void shouldRespectUseStrictExpression() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
page.evaluate("() => {\n" +
" 'use strict';\n" +
" // @ts-ignore\n" +
@@ -508,8 +526,10 @@ public class TestPageEvaluate extends TestBase {
" // @ts-ignore\n" +
" return variableY;\n" +
"}");
});
assertTrue(e.getMessage().contains("variableY"));
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("variableY"));
}
}
@Test
@@ -519,8 +539,12 @@ public class TestPageEvaluate extends TestBase {
@Test
void shouldNotLeakHandles() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.evaluate("handles.length"));
assertTrue(e.getMessage().contains(" handles"));
try {
page.evaluate("handles.length");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains(" handles"));
}
}
@Test
@@ -532,13 +556,16 @@ public class TestPageEvaluate extends TestBase {
@Test
void shouldEvaluateException() {
String result = (String) page.evaluate("() => {\n" +
" return (function functionOnStack() {\n" +
" return new Error('error message');\n" +
" })();\n" +
"}");
assertTrue(result.contains("Error: error message"));
assertTrue(result.contains("functionOnStack"));
try {
page.evaluate("() => {\n" +
" return (function functionOnStack() {\n" +
" return new Error('error message');\n" +
" })();\n" +
"}");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Error: error message"));
assertTrue(e.getMessage().contains("functionOnStack"));
}
}
@Test
@@ -547,56 +574,20 @@ public class TestPageEvaluate extends TestBase {
assertTrue(((String) error).contains("Error: error message"));
}
@Test
void shouldEvaluateDate() {
Object result = page.evaluate("() => ({ date: new Date('2020-05-27T01:31:38.506Z') })");
Date expected = Date.from(ZonedDateTime.parse("2020-05-27T01:31:38.506Z").toInstant());
assertEquals(mapOf("date", expected), result);
// TODO: Date values are not supported in java.
}
@Test
void shouldRoundtripDate() {
Date date = Date.from(ZonedDateTime.parse("2020-05-27T01:31:38.506Z").toInstant());
Object result = page.evaluate("date => date", date);
assertTrue(result instanceof Date);
assertEquals(date.toString(), result.toString());
// TODO: Date values are not supported in java.
}
@Test
void shouldRoundtripRegex() {
Pattern regex = Pattern.compile("hello", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
Object result = page.evaluate("regex => regex", regex);
assertTrue(result instanceof Pattern);
assertEquals(regex.toString(), result.toString());
assertEquals(regex.flags(), ((Pattern)result).flags());
// Not applicable
}
@Test
void shouldJsonValueDate() {
JSHandle resultHandle = page.evaluateHandle("() => ({ date: new Date('2020-05-27T01:31:38.506Z') })");
assertEquals(mapOf("date", Date.from(ZonedDateTime.parse("2020-05-27T01:31:38.506Z").toInstant())), resultHandle.jsonValue());
}
@Test
void shouldEvaluateUrl() throws MalformedURLException {
Object result = page.evaluate("() => ({ url: new URL('https://example.com/') })");
assertEquals(mapOf("url", new URL("https://example.com/")), result);
}
@Test
void shouldRoundtripUrl() throws MalformedURLException {
URL url = new URL("https://example.com/");
Object result = page.evaluate("url => url", url);
assertTrue(result instanceof URL);
assertEquals(url.toString(), result.toString());
}
@Test
void shouldRoundtripComplexUrl() throws MalformedURLException {
URL url = new URL("https://user:password@www.contoso.com:80/Home/Index.htm?q1=v1&q2=v2#FragmentName");
Object result = page.evaluate("url => url", url);
assertTrue(result instanceof URL);
assertEquals(url.toString(), result.toString());
// TODO: Date values are not supported in java.
}
@Test
@@ -629,13 +620,4 @@ public class TestPageEvaluate extends TestBase {
assertEquals(1, map.size());
assertTrue(map == map.get("b"));
}
@Test
void shouldAcceptParameter() {
Instant instant = Instant.now();
LocalDateTime localDateTime = instant.atZone(ZoneId.systemDefault()).toLocalDateTime();
Object object = page.evaluate("p => p", localDateTime);
assertTrue(object instanceof Date);
assertEquals(Date.from(instant), object);
}
}
@@ -196,10 +196,12 @@ public class TestPageExposeFunction extends TestBase {
@Test
void shouldThrowForDuplicateRegistrations() {
page.exposeFunction("foo", args -> null);
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
page.exposeFunction("foo", args -> null);
});
assertTrue(e.getMessage().contains("Function \"foo\" has been already registered"));
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Function \"foo\" has been already registered"));
}
}
@Test
@@ -216,12 +218,14 @@ public class TestPageExposeFunction extends TestBase {
assertEquals(17, page.evaluate("async function() {\n" +
" return window['logme'](undefined, undefined, undefined);\n" +
"}"));
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
page.evaluate("async function() {\n" +
" return window['logme'](1, 2);\n" +
"}");
});
assertTrue(e.getMessage().contains("exposeBindingHandle supports a single argument, 2 received"));
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("exposeBindingHandle supports a single argument, 2 received"));
}
}
@Test
@@ -43,8 +43,12 @@ public class TestPageFill extends TestBase {
page.navigate(server.PREFIX + "/input/textarea.html");
for (String type : new String[]{"button", "checkbox", "file", "image", "radio", "reset", "submit"}) {
page.evalOnSelector("input", "(input, type) => input.setAttribute('type', type)", type);
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.fill("input", ""));
assertTrue(e.getMessage().contains("input of type \"" + type + "\" cannot be filled"), "type = " + type + e.getMessage());
try {
page.fill("input", "");
fail("fill should throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("input of type \"" + type + "\" cannot be filled"), "type = " + type + e.getMessage());
}
}
}
@@ -58,14 +62,24 @@ public class TestPageFill extends TestBase {
@Test
void shouldThrowOnIncorrectRangeValue() {
page.setContent("<input type=range min=0 max=100 value=50>");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.fill("input", "foo"));
assertTrue(e.getMessage().contains("Malformed value"), e.getMessage());
e = assertThrows(PlaywrightException.class, () -> page.fill("input", "200"));
assertTrue(e.getMessage().contains("Malformed value"), e.getMessage());
e = assertThrows(PlaywrightException.class, () -> page.fill("input", "15.43"));
assertTrue(e.getMessage().contains("Malformed value"), e.getMessage());
try {
page.fill("input", "foo");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Malformed value"), e.getMessage());
}
try {
page.fill("input", "200");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Malformed value"), e.getMessage());
}
try {
page.fill("input", "15.43");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Malformed value"), e.getMessage());
}
}
@@ -91,8 +105,12 @@ public class TestPageFill extends TestBase {
@DisabledIf(value="com.microsoft.playwright.TestBase#isWebKit", disabledReason="skip")
void shouldThrowOnIncorrectDate() {
page.setContent("<input type=date>");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.fill("input", "2020-13-05"));
assertTrue(e.getMessage().contains("Malformed value"));
try {
page.fill("input", "2020-13-05");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Malformed value"));
}
}
@Test
@@ -106,8 +124,12 @@ public class TestPageFill extends TestBase {
@DisabledIf(value="com.microsoft.playwright.TestBase#isWebKit", disabledReason="skip")
void shouldThrowOnIncorrectTime() {
page.setContent("<input type=time>");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.fill("input", "25:05"));
assertTrue(e.getMessage().contains("Malformed value"));
try {
page.fill("input", "25:05");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Malformed value"));
}
}
@Test
@@ -121,8 +143,12 @@ public class TestPageFill extends TestBase {
@EnabledIf(value="com.microsoft.playwright.TestBase#isChromium", disabledReason="skip")
void shouldThrowOnIncorrectDatetimeLocal() {
page.setContent("<input type=datetime-local>");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.fill("input", "abc"));
assertTrue(e.getMessage().contains("Malformed value"));
try {
page.fill("input", "abc");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Malformed value"));
}
}
@Test
@@ -162,8 +188,12 @@ public class TestPageFill extends TestBase {
@Test
void shouldThrowWhenElementIsNotAnInputTextareaOrContenteditable() {
page.navigate(server.PREFIX + "/input/textarea.html");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.fill("body", ""));
assertTrue(e.getMessage().contains("Element is not an <input>"));
try {
page.fill("body", "");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Element is not an <input>"));
}
}
void shouldThrowIfPassedANonStringValue() {
@@ -222,8 +252,12 @@ public class TestPageFill extends TestBase {
@Test
void shouldNotBeAbleToFillTextIntoTheInputTypeNumber() {
page.setContent("<input id='input' type='number'></input>");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.fill("input", "abc"));
assertTrue(e.getMessage().contains("Cannot type text into input[type=number]"));
try {
page.fill("input", "abc");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Cannot type text into input[type=number]"));
}
}
@Test
@@ -295,14 +295,24 @@ public class TestPageKeyboard extends TestBase {
@Test
void shouldThrowOnUnknownKeys() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.keyboard().press("NotARealKey"));
assertTrue(e.getMessage().contains("Unknown key: \"NotARealKey\""), "Expecting Exception: " + e.getMessage() + " contain: Unknown key: \"NotARealKey\"");
e = assertThrows(PlaywrightException.class, () -> page.keyboard().press("ё"));
assertTrue(e.getMessage().contains("Unknown key: \"ё\""), "Expecting Exception: " + e.getMessage() + " contain: Unknown key: \"ё\"");
e = assertThrows(PlaywrightException.class, () -> page.keyboard().press("😊"));
assertTrue(e.getMessage().contains("Unknown key: \"😊\""), "Expecting Exception: " + e.getMessage() + " contain: Unknown key: \"😊\"");
try {
page.keyboard().press("NotARealKey");
fail("did not throw");
} catch (Exception e) {
assertTrue(e.getMessage().contains("Unknown key: \"NotARealKey\""), "Expecting Exception: " + e.getMessage() + " contain: Unknown key: \"NotARealKey\"");
}
try {
page.keyboard().press("ё");
fail("did not throw");
} catch (Exception e) {
assertTrue(e.getMessage().contains("Unknown key: \"ё\""), "Expecting Exception: " + e.getMessage() + " contain: Unknown key: \"ё\"");
}
try {
page.keyboard().press("😊");
fail("did not throw");
} catch (Exception e) {
assertTrue(e.getMessage().contains("Unknown key: \"😊\""), "Expecting Exception: " + e.getMessage() + " contain: Unknown key: \"😊\"");
}
}
@Test
@@ -52,28 +52,34 @@ public class TestPageLocatorQuery extends TestBase {
@Test
void shouldThrowOnCaptureWNth() {
page.setContent("<section><div><p>A</p></div></section>");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
page.locator("*css=div >> p").nth(1).click();
});
assertTrue(e.getMessage().contains("Can't query n-th element"), e.getMessage());
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Can't query n-th element"), e.getMessage());
}
}
@Test
void shouldThrowOnDueToStrictness() {
page.setContent("<div>A</div><div>B</div>");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
page.locator("div").isVisible();
});
assertTrue(e.getMessage().contains("strict mode violation"), e.getMessage());
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("strict mode violation"), e.getMessage());
}
}
@Test
void shouldThrowOnDueToStrictness2() {
page.setContent("<select><option>One</option><option>Two</option></select>");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
try {
page.locator("option").evaluate("e => {}");
});
assertTrue(e.getMessage().contains("strict mode violation"), e.getMessage());
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("strict mode violation"), e.getMessage());
}
}
@Test
@@ -113,33 +119,6 @@ public class TestPageLocatorQuery extends TestBase {
assertEquals("Hello \"world\"", page.locator("div", new Page.LocatorOptions().setHasText(pattern)).textContent());
}
@Test
void shouldFilterByCaseInsensitiveRegexInAChild() {
page.setContent("<div class=\"test\"><h5>Title Text</h5></div>");
Pattern pattern = Pattern.compile("^title text$", Pattern.CASE_INSENSITIVE);
assertThat(page.locator("div", new Page.LocatorOptions().setHasText(pattern))).hasText("Title Text");
}
@Test
void shouldFilterByCaseInsensitiveRegexInMultipleChildren() {
page.setContent("<div class=\"test\"><h5>Title</h5> <h2><i>Text</i></h2></div>`");
Pattern pattern = Pattern.compile("^title text$", Pattern.CASE_INSENSITIVE);
assertThat(page.locator("div", new Page.LocatorOptions().setHasText(pattern))).hasClass("test");
}
@Test
void shouldFilterByRegexWithSpecialSymbols() {
page.setContent("<div class=\"test\"><h5>First/\"and\"</h5><h2><i>Second\\</i></h2></div>");
Pattern pattern = Pattern.compile("first\\/\".*\"second\\\\$", Pattern.CASE_INSENSITIVE);
assertThat(page.locator("div", new Page.LocatorOptions().setHasText(pattern))).hasClass("test");
}
@Test
void shouldFilterByTextWithAmpersand() {
page.setContent("<div>Save & Continue</div>");
assertEquals("Save & Continue", page.locator("div",
new Page.LocatorOptions().setHasText("Save & Continue")).textContent());
}
@Test
void shouldSupportHasLocator() {
page.setContent("<div><span>hello</span></div><div><span>world</span></div>");

Some files were not shown because too many files have changed in this diff Show More