NOTE: If you want to debug where the mouse moved, you can use the Trace viewer or Playwright Inspector. A red dot showing the location of the + * mouse will be shown for every mouse action. + * *
Every {@code page} object has its own Mouse, accessible with {@link com.microsoft.playwright.Page#mouse Page.mouse()}. *
{@code
* // Using ‘page.mouse’ to trace a 100x100 square.
diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/AssertionsBase.java b/playwright/src/main/java/com/microsoft/playwright/impl/AssertionsBase.java
index 92ad7ef3c..c97796032 100644
--- a/playwright/src/main/java/com/microsoft/playwright/impl/AssertionsBase.java
+++ b/playwright/src/main/java/com/microsoft/playwright/impl/AssertionsBase.java
@@ -16,7 +16,6 @@
package com.microsoft.playwright.impl;
-import com.microsoft.playwright.PlaywrightException;
import org.opentest4j.AssertionFailedError;
import org.opentest4j.ValueWrapper;
@@ -29,12 +28,10 @@
import static com.microsoft.playwright.impl.Utils.toJsRegexFlags;
import static java.util.Arrays.asList;
-class AssertionsBase {
- final LocatorImpl actualLocator;
+abstract class AssertionsBase {
final boolean isNot;
- AssertionsBase(LocatorImpl actual, boolean isNot) {
- this.actualLocator = actual;
+ AssertionsBase(boolean isNot) {
this.isNot = isNot;
}
@@ -58,7 +55,7 @@ void expectImpl(String expression, FrameExpectOptions expectOptions, Object expe
if (isNot) {
message = message.replace("expected to", "expected not to");
}
- FrameExpectResult result = actualLocator.expect(expression, expectOptions, title);
+ FrameExpectResult result = doExpect(expression, expectOptions, title);
if (result.matches == isNot) {
Object actual = result.received == null ? null : Serialization.deserialize(result.received);
String log = (result.log == null) ? "" : String.join("\n", result.log);
@@ -75,7 +72,9 @@ void expectImpl(String expression, FrameExpectOptions expectOptions, Object expe
}
}
- private static ValueWrapper formatValue(Object value) {
+ abstract FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title);
+
+ protected static ValueWrapper formatValue(Object value) {
if (value == null || !value.getClass().isArray()) {
return ValueWrapper.create(value);
}
diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/BrowserContextImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/BrowserContextImpl.java
index b1f21d880..55a1aec42 100644
--- a/playwright/src/main/java/com/microsoft/playwright/impl/BrowserContextImpl.java
+++ b/playwright/src/main/java/com/microsoft/playwright/impl/BrowserContextImpl.java
@@ -506,7 +506,7 @@ private void routeWebSocketImpl(UrlMatcher matcher, Consumer han
void recordIntoHar(PageImpl page, Path har, RouteFromHAROptions options, HarContentPolicy contentPolicy) {
if (contentPolicy == null) {
- contentPolicy = Utils.convertType(options.updateContent, HarContentPolicy.class);;
+ contentPolicy = Utils.convertType(options.updateContent, HarContentPolicy.class);
}
if (contentPolicy == null) {
contentPolicy = HarContentPolicy.ATTACH;
diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/ConsoleMessageImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/ConsoleMessageImpl.java
index e5aa1af1f..f199c26f8 100644
--- a/playwright/src/main/java/com/microsoft/playwright/impl/ConsoleMessageImpl.java
+++ b/playwright/src/main/java/com/microsoft/playwright/impl/ConsoleMessageImpl.java
@@ -20,13 +20,10 @@
import com.google.gson.JsonObject;
import com.microsoft.playwright.ConsoleMessage;
import com.microsoft.playwright.JSHandle;
-import com.microsoft.playwright.Page;
import java.util.ArrayList;
import java.util.List;
-import static com.microsoft.playwright.impl.Serialization.gson;
-
public class ConsoleMessageImpl implements ConsoleMessage {
private final Connection connection;
private PageImpl page;
diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/FrameImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/FrameImpl.java
index 5f1a0a53d..ac04719ab 100644
--- a/playwright/src/main/java/com/microsoft/playwright/impl/FrameImpl.java
+++ b/playwright/src/main/java/com/microsoft/playwright/impl/FrameImpl.java
@@ -993,7 +993,8 @@ ElementHandle waitForSelectorImpl(String selector, WaitForSelectorOptions option
@Override
public void waitForTimeout(double timeout) {
JsonObject params = new JsonObject();
- sendMessage("waitForTimeout", params, timeout);
+ params.addProperty("waitTimeout", timeout);
+ sendMessage("waitForTimeout", params, NO_TIMEOUT);
}
@Override
@@ -1085,4 +1086,16 @@ protected double navigationTimeout(Double timeout) {
}
return new TimeoutSettings().navigationTimeout(timeout);
}
+
+ FrameExpectResult expect(String expression, FrameExpectOptions options, String title) {
+ return withTitle(title, () -> expect(expression, options));
+ }
+
+ FrameExpectResult expect(String expression, FrameExpectOptions options) {
+ JsonObject params = gson().toJsonTree(options).getAsJsonObject();
+ params.addProperty("expression", expression);
+ JsonElement json = sendMessage("expect", params, options.timeout);
+ FrameExpectResult result = gson().fromJson(json, FrameExpectResult.class);
+ return result;
+ }
}
diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/LocatorAssertionsImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/LocatorAssertionsImpl.java
index 616366b06..088910c98 100644
--- a/playwright/src/main/java/com/microsoft/playwright/impl/LocatorAssertionsImpl.java
+++ b/playwright/src/main/java/com/microsoft/playwright/impl/LocatorAssertionsImpl.java
@@ -30,12 +30,20 @@
import static com.microsoft.playwright.impl.Utils.convertType;
public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAssertions {
+ LocatorImpl actualLocator;
+
public LocatorAssertionsImpl(Locator locator) {
this(locator, false);
}
private LocatorAssertionsImpl(Locator locator, boolean isNot) {
- super((LocatorImpl) locator, isNot);
+ super(isNot);
+ this.actualLocator = (LocatorImpl) locator;
+ }
+
+ @Override
+ FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title) {
+ return actualLocator.expect(expression, expectOptions, title);
}
diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/LocatorImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/LocatorImpl.java
index f27a3d43f..7c182ad3c 100644
--- a/playwright/src/main/java/com/microsoft/playwright/impl/LocatorImpl.java
+++ b/playwright/src/main/java/com/microsoft/playwright/impl/LocatorImpl.java
@@ -645,7 +645,8 @@ public int hashCode() {
}
FrameExpectResult expect(String expression, FrameExpectOptions options, String title) {
- return frame.withTitle(title, () -> expectImpl(expression, options));
+ options.selector = selector;
+ return frame.expect(expression, options, title);
}
JsonObject toProtocol() {
@@ -654,13 +655,4 @@ JsonObject toProtocol() {
result.addProperty("selector", selector);
return result;
}
-
- private FrameExpectResult expectImpl(String expression, FrameExpectOptions options) {
- JsonObject params = gson().toJsonTree(options).getAsJsonObject();
- params.addProperty("selector", selector);
- params.addProperty("expression", expression);
- JsonElement json = frame.sendMessage("expect", params, options.timeout);
- FrameExpectResult result = gson().fromJson(json, FrameExpectResult.class);
- return result;
- }
}
diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/PageAssertionsImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/PageAssertionsImpl.java
index e4c113834..9a114f249 100644
--- a/playwright/src/main/java/com/microsoft/playwright/impl/PageAssertionsImpl.java
+++ b/playwright/src/main/java/com/microsoft/playwright/impl/PageAssertionsImpl.java
@@ -32,10 +32,16 @@ public PageAssertionsImpl(Page page) {
}
private PageAssertionsImpl(Page page, boolean isNot) {
- super((LocatorImpl) page.locator(":root"), isNot);
+ super(isNot);
this.actualPage = (PageImpl) page;
}
+ @Override
+ FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title) {
+ FrameImpl frame = (FrameImpl) actualPage.mainFrame();
+ return frame.expect(expression, expectOptions, title);
+ }
+
@Override
public void hasTitle(String title, HasTitleOptions options) {
ExpectedTextValue expected = new ExpectedTextValue();
diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/Protocol.java b/playwright/src/main/java/com/microsoft/playwright/impl/Protocol.java
index 2caef1409..c1a1768b1 100644
--- a/playwright/src/main/java/com/microsoft/playwright/impl/Protocol.java
+++ b/playwright/src/main/java/com/microsoft/playwright/impl/Protocol.java
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-// This file is generated by generate_java_rpc.js, do not edit manually.
-
package com.microsoft.playwright.impl;
import java.util.List;
@@ -105,6 +103,7 @@ class ExpectedTextValue {
class FrameExpectOptions {
Object expressionArg;
List expectedText;
+ String selector;
Double expectedNumber;
SerializedArgument expectedValue;
Boolean useInnerText;
diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/SelectorsImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/SelectorsImpl.java
index 62f5779be..878542ef1 100644
--- a/playwright/src/main/java/com/microsoft/playwright/impl/SelectorsImpl.java
+++ b/playwright/src/main/java/com/microsoft/playwright/impl/SelectorsImpl.java
@@ -68,6 +68,10 @@ public void register(String name, Path path, RegisterOptions options) {
}
private void registerImpl(String name, String script, RegisterOptions options) {
+ if (selectorEngines.stream().anyMatch(engine -> name.equals(engine.get("name").getAsString()))) {
+ throw new PlaywrightException("selectors.register: \"" + name + "\" selector engine has been already registered");
+ }
+
JsonObject engine = new JsonObject();
engine.addProperty("name", name);
engine.addProperty("source", script);
diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/WebSocketRouteImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/WebSocketRouteImpl.java
index 53479fcf2..ab9ed40a0 100644
--- a/playwright/src/main/java/com/microsoft/playwright/impl/WebSocketRouteImpl.java
+++ b/playwright/src/main/java/com/microsoft/playwright/impl/WebSocketRouteImpl.java
@@ -128,7 +128,11 @@ void afterHandle() {
return;
}
// Ensure that websocket is "open" and can send messages without an actual server connection.
- sendMessageAsync("ensureOpened");
+ try {
+ sendMessageAsync("ensureOpened");
+ } catch (PlaywrightException e) {
+ // If this happens after the page has been closed, ignore the error.
+ }
}
@Override
diff --git a/playwright/src/main/java/com/microsoft/playwright/options/Cookie.java b/playwright/src/main/java/com/microsoft/playwright/options/Cookie.java
index ae3881329..ee7888536 100644
--- a/playwright/src/main/java/com/microsoft/playwright/options/Cookie.java
+++ b/playwright/src/main/java/com/microsoft/playwright/options/Cookie.java
@@ -48,6 +48,12 @@ public class Cookie {
* Optional.
*/
public SameSiteAttribute sameSite;
+ /**
+ * For partitioned third-party cookies (aka CHIPS), the
+ * partition key. Optional.
+ */
+ public String partitionKey;
public Cookie(String name, String value) {
this.name = name;
@@ -103,4 +109,13 @@ public Cookie setSameSite(SameSiteAttribute sameSite) {
this.sameSite = sameSite;
return this;
}
+ /**
+ * For partitioned third-party cookies (aka CHIPS), the
+ * partition key. Optional.
+ */
+ public Cookie setPartitionKey(String partitionKey) {
+ this.partitionKey = partitionKey;
+ return this;
+ }
}
\ No newline at end of file
diff --git a/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextFetch.java b/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextFetch.java
index f8592f82e..d7352c748 100644
--- a/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextFetch.java
+++ b/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextFetch.java
@@ -436,7 +436,7 @@ void shouldSupportTimeoutOption() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
context.request().get(server.PREFIX + "/slow", RequestOptions.create().setTimeout(100));
});
- assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
+ assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}
@Test
@@ -468,7 +468,7 @@ void shouldRespectTimeoutAfterRedirects() {
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());
+ assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}
@Test
diff --git a/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextStorageState.java b/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextStorageState.java
index 4d62fec4f..a398aaba0 100644
--- a/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextStorageState.java
+++ b/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextStorageState.java
@@ -174,10 +174,19 @@ void shouldSerialiseStorageStateWithLoneSurrogates() {
@Test
void shouldSupportIndexedDB() {
page.navigate(server.PREFIX + "/to-do-notifications/index.html");
+
+ assertThat(page.locator("#notifications")).matchesAriaSnapshot(
+ " - list:\n" +
+ " - listitem: Database initialised."
+ );
page.locator("label:has-text('Task title')").fill("Pet the cat");
page.locator("label:has-text('Hours')").fill("1");
page.locator("label:has-text('Mins')").fill("1");
page.locator("text=Add Task").click();
+ assertThat(page.locator("#notifications")).matchesAriaSnapshot(
+ " - list:\n" +
+ " - listitem: \"Transaction completed: database modification finished.\""
+ );
String storageState = page.context().storageState(new BrowserContext.StorageStateOptions().setIndexedDB(true));
assertJsonEquals("{\"cookies\":[],\"origins\":[\n" +
diff --git a/playwright/src/test/java/com/microsoft/playwright/TestChromiumTracing.java b/playwright/src/test/java/com/microsoft/playwright/TestChromiumTracing.java
index 034d464c4..93d1a220c 100644
--- a/playwright/src/test/java/com/microsoft/playwright/TestChromiumTracing.java
+++ b/playwright/src/test/java/com/microsoft/playwright/TestChromiumTracing.java
@@ -63,12 +63,22 @@ void shouldRunWithCustomCategoriesIfProvided(@TempDir Path tempDir) throws IOExc
Path outputTraceFile = tempDir.resolve("trace.json");
browser.startTracing(page, new Browser.StartTracingOptions()
.setPath(outputTraceFile)
- .setCategories(asList("disabled-by-default-v8.cpu_profiler.hires")));
+ .setCategories(asList("disabled-by-default-cc.debug")));
+ page.evaluate("() => 1 + 1");
browser.stopTracing();
try (FileReader fileReader = new FileReader(outputTraceFile.toFile())) {
JsonObject traceJson = new Gson().fromJson(fileReader, JsonObject.class);
- assertTrue(traceJson.getAsJsonObject("metadata").get("trace-config")
- .getAsString().contains("disabled-by-default-v8.cpu_profiler.hires"));
+ // NOTE: trace-config is deprecated as per http://crrev.com/c/6628182
+ boolean hasTraceConfig =
+ traceJson.getAsJsonObject("metadata").get("trace-config") != null
+ && traceJson.getAsJsonObject("metadata").get("trace-config").getAsString().contains("disabled-by-default-cc.debug");
+ boolean hasTraceEvents = traceJson.getAsJsonArray("traceEvents").asList().stream()
+ .anyMatch(event -> {
+ JsonObject eventObj = (JsonObject) event;
+ return eventObj.has("cat") &&
+ eventObj.get("cat").getAsString().equals("disabled-by-default-cc.debug");
+ });
+ assertTrue(hasTraceConfig || hasTraceEvents);
}
}
}
diff --git a/playwright/src/test/java/com/microsoft/playwright/TestGlobalFetch.java b/playwright/src/test/java/com/microsoft/playwright/TestGlobalFetch.java
index f11e39f22..ce9e21f48 100644
--- a/playwright/src/test/java/com/microsoft/playwright/TestGlobalFetch.java
+++ b/playwright/src/test/java/com/microsoft/playwright/TestGlobalFetch.java
@@ -189,7 +189,7 @@ void shouldSupportGlobalTimeoutOption() {
APIRequestContext request = playwright.request().newContext(new APIRequest.NewContextOptions().setTimeout(100));
server.setRoute("/empty.html", exchange -> {});
PlaywrightException e = assertThrows(PlaywrightException.class, () -> request.get(server.EMPTY_PAGE));
- assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
+ assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}
diff --git a/playwright/src/test/java/com/microsoft/playwright/TestPageAddLocatorHandler.java b/playwright/src/test/java/com/microsoft/playwright/TestPageAddLocatorHandler.java
index 49a615f4f..5b5cab3e2 100644
--- a/playwright/src/test/java/com/microsoft/playwright/TestPageAddLocatorHandler.java
+++ b/playwright/src/test/java/com/microsoft/playwright/TestPageAddLocatorHandler.java
@@ -271,7 +271,7 @@ public void shouldWaitForHiddenByDefault2() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.locator("#target").click(new Locator.ClickOptions().setTimeout(3_000)));
assertEquals(0, (int) page.evaluate("window.clicked"));
- assertThat(page.locator("#interstitial")).isVisible();
+ assertTrue(page.locator("#interstitial").isVisible());
assertEquals(1, called[0]);
assertTrue(e.getMessage().contains("locator handler has finished, waiting for getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName(\"close\")) to be hidden"), e.getMessage());
}
diff --git a/playwright/src/test/java/com/microsoft/playwright/TestPageAriaSnapshot.java b/playwright/src/test/java/com/microsoft/playwright/TestPageAriaSnapshot.java
index 527e0d7b7..7dd9c8dfa 100644
--- a/playwright/src/test/java/com/microsoft/playwright/TestPageAriaSnapshot.java
+++ b/playwright/src/test/java/com/microsoft/playwright/TestPageAriaSnapshot.java
@@ -3,6 +3,7 @@
import com.microsoft.playwright.junit.FixtureTest;
import com.microsoft.playwright.junit.UsePlaywright;
import org.junit.jupiter.api.Test;
+import org.opentest4j.AssertionFailedError;
import java.util.Arrays;
import java.util.List;
@@ -12,6 +13,7 @@
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
@FixtureTest
@UsePlaywright
@@ -102,4 +104,27 @@ void shouldMatchUrl(Page page) {
"- link:\n" +
" - /url: /.*example.com/");
}
+
+ @Test
+ void shouldHandleTopLevelDeepEqual(Page page) {
+ // https://github.com/microsoft/playwright/issues/36456
+ page.setContent("" +
+ "\n" +
+ " - \n" +
+ "
\n" +
+ " - 1.1
\n" +
+ " - 1.2
\n" +
+ "
\n" +
+ " \n" +
+ "
");
+
+ assertThrows(AssertionFailedError.class, () -> {
+ assertThat(page.locator("body")).matchesAriaSnapshot("" +
+ "- /children: deep-equal\n" +
+ "- list:\n" +
+ " - listitem:\n" +
+ " - listitem: \"1.1\"\n" +
+ " - listitem: \"1.2\"");
+ });
+ }
}
diff --git a/playwright/src/test/java/com/microsoft/playwright/TestPageInterception.java b/playwright/src/test/java/com/microsoft/playwright/TestPageInterception.java
index a6462ff22..907d37bbc 100644
--- a/playwright/src/test/java/com/microsoft/playwright/TestPageInterception.java
+++ b/playwright/src/test/java/com/microsoft/playwright/TestPageInterception.java
@@ -99,7 +99,7 @@ void shouldSupportTimeoutOptionInRouteFetch() {
page.route("**/*", route -> {
PlaywrightException error = assertThrows(PlaywrightException.class,
() -> route.fetch(new Route.FetchOptions().setTimeout(1000)));
- assertTrue(error.getMessage().contains("Request timed out after 1000ms"), error.getMessage());
+ assertTrue(error.getMessage().contains("Timeout 1000ms exceeded"), error.getMessage());
});
PlaywrightException error = assertThrows(PlaywrightException.class,
() -> page.navigate(server.PREFIX + "/slow", new Page.NavigateOptions().setTimeout(2000)));
@@ -198,6 +198,15 @@ void shouldWorkWithGlob() {
assertTrue(urlMatches("http://playwright.dev/foo", "http://playwright.dev/foo?bar", "\\\\?bar"));
assertTrue(urlMatches("http://first.host/", "http://second.host/foo", "**/foo"));
assertTrue(urlMatches("http://playwright.dev/", "http://localhost/", "*//localhost/"));
+
+ String[] customPrefixes = {"about", "data", "chrome", "edge", "file"};
+ for (String prefix : customPrefixes) {
+ assertTrue(urlMatches("http://playwright.dev/", prefix + ":blank", prefix + ":blank"));
+ assertFalse(urlMatches("http://playwright.dev/", prefix + ":blank", "http://playwright.dev/"));
+ assertTrue(urlMatches(null, prefix + ":blank", prefix + ":blank"));
+ assertTrue(urlMatches(null, prefix + ":blank", prefix + ":*"));
+ assertFalse(urlMatches(null, "not" + prefix + ":blank", prefix + ":*"));
+ }
}
Pattern globToRegex(String glob) {
diff --git a/playwright/src/test/java/com/microsoft/playwright/TestSelectorsRegister.java b/playwright/src/test/java/com/microsoft/playwright/TestSelectorsRegister.java
index 4d50891ce..1c6cbcc0c 100644
--- a/playwright/src/test/java/com/microsoft/playwright/TestSelectorsRegister.java
+++ b/playwright/src/test/java/com/microsoft/playwright/TestSelectorsRegister.java
@@ -23,25 +23,26 @@
import static org.junit.jupiter.api.Assertions.*;
public class TestSelectorsRegister extends TestBase {
+ private static final String TAG_SELECTOR_SCRIPT = "{\n" +
+ " create(root, target) {\n" +
+ " return target.nodeName;\n" +
+ " },\n" +
+ " query(root, selector) {\n" +
+ " return root.querySelector(selector);\n" +
+ " },\n" +
+ " queryAll(root, selector) {\n" +
+ " return Array.from(root.querySelectorAll(selector));\n" +
+ " }\n" +
+ "}";
+
@Test
void shouldWork() {
- String selectorScript = "{\n" +
- " create(root, target) {\n" +
- " return target.nodeName;\n" +
- " },\n" +
- " query(root, selector) {\n" +
- " return root.querySelector(selector);\n" +
- " },\n" +
- " queryAll(root, selector) {\n" +
- " return Array.from(root.querySelectorAll(selector));\n" +
- " }\n" +
- "}";
// Register one engine before creating context.
- playwright.selectors().register("tag", selectorScript);
+ playwright.selectors().register("tag", TAG_SELECTOR_SCRIPT);
BrowserContext context = browser.newContext();
// Register another engine after creating context.
- playwright.selectors().register("tag2", selectorScript);
+ playwright.selectors().register("tag2", TAG_SELECTOR_SCRIPT);
Page page = context.newPage();
page.setContent("");
@@ -134,4 +135,21 @@ void shouldHandleErrors() {
});
assertTrue(e.getMessage().contains("\"css\" is a predefined selector engine"));
}
+
+ @Test
+ void shouldThrowAlreadyRegisteredErrorWhenRegistering() {
+ // https://github.com/microsoft/playwright/issues/36467
+
+ // this test is about the exception *before* there's a context created
+ context.close();
+
+ // Register the selector engine first
+ playwright.selectors().register("alreadyRegistered", TAG_SELECTOR_SCRIPT);
+
+ // Attempt to register the same selector engine again should throw an error
+ PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
+ playwright.selectors().register("alreadyRegistered", TAG_SELECTOR_SCRIPT);
+ });
+ assertTrue(e.getMessage().contains("\"alreadyRegistered\" selector engine has been already registered"));
+ }
}
diff --git a/scripts/DRIVER_VERSION b/scripts/DRIVER_VERSION
index 9adccc2f2..8ba9de6a3 100644
--- a/scripts/DRIVER_VERSION
+++ b/scripts/DRIVER_VERSION
@@ -1 +1 @@
-1.53.1
+1.54.0-alpha-2025-07-09